Support human NPCs for identifiers.

This commit is contained in:
Ottermandias 2023-07-12 02:44:04 +02:00
parent a310e01296
commit b00e6bd98b
17 changed files with 536 additions and 162 deletions

View file

@ -68,24 +68,27 @@ public class AutoDesignApplier : IDisposable
case AutomationChanged.Type.ChangedDesign: case AutomationChanged.Type.ChangedDesign:
case AutomationChanged.Type.ChangedConditions: case AutomationChanged.Type.ChangedConditions:
_objects.Update(); _objects.Update();
if (_objects.TryGetValue(set.Identifier, out var data)) foreach (var id1 in set.Identifiers)
{ {
if (_state.GetOrCreate(set.Identifier, data.Objects[0], out var state)) if (_objects.TryGetValue(id1, out var data))
{ {
Reduce(data.Objects[0], state, set, false); if (_state.GetOrCreate(id1, data.Objects[0], out var state))
foreach (var actor in data.Objects)
_state.ReapplyState(actor);
}
}
else if (_objects.TryGetValueAllWorld(set.Identifier, out data))
{
foreach (var actor in data.Objects)
{
var id = actor.GetIdentifier(_actors.AwaitedService);
if (_state.GetOrCreate(id, actor, out var state))
{ {
Reduce(actor, state, set, false); Reduce(data.Objects[0], state, set, false);
_state.ReapplyState(actor); foreach (var actor in data.Objects)
_state.ReapplyState(actor);
}
}
else if (_objects.TryGetValueAllWorld(id1, out data))
{
foreach (var actor in data.Objects)
{
var id = actor.GetIdentifier(_actors.AwaitedService);
if (_state.GetOrCreate(id, actor, out var state))
{
Reduce(actor, state, set, false);
_state.ReapplyState(actor);
}
} }
} }
} }
@ -265,6 +268,10 @@ public class AutoDesignApplier : IDisposable
var customize = state.ModelData.Customize; var customize = state.ModelData.Customize;
CustomizeFlag fixFlags = 0; CustomizeFlag fixFlags = 0;
// Skip anything not human.
if (!state.ModelData.IsHuman || !design.IsHuman)
return;
// Skip invalid designs entirely. // Skip invalid designs entirely.
if (_config.SkipInvalidCustomizations if (_config.SkipInvalidCustomizations
&& !_code.EnabledMesmer && !_code.EnabledMesmer

View file

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using Dalamud.Utility; using Dalamud.Utility;
using Glamourer.Designs; using Glamourer.Designs;
@ -11,7 +12,6 @@ using Glamourer.Events;
using Glamourer.Interop; using Glamourer.Interop;
using Glamourer.Services; using Glamourer.Services;
using Glamourer.Structs; using Glamourer.Structs;
using Glamourer.Unlocks;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui.Filesystem; using OtterGui.Filesystem;
@ -29,7 +29,6 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
private readonly DesignManager _designs; private readonly DesignManager _designs;
private readonly ActorService _actors; private readonly ActorService _actors;
private readonly AutomationChanged _event; private readonly AutomationChanged _event;
private readonly ItemUnlockManager _unlockManager;
private readonly List<AutoDesignSet> _data = new(); private readonly List<AutoDesignSet> _data = new();
private readonly Dictionary<ActorIdentifier, AutoDesignSet> _enabled = new(); private readonly Dictionary<ActorIdentifier, AutoDesignSet> _enabled = new();
@ -38,14 +37,13 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
=> _enabled; => _enabled;
public AutoDesignManager(JobService jobs, ActorService actors, SaveService saveService, DesignManager designs, AutomationChanged @event, public AutoDesignManager(JobService jobs, ActorService actors, SaveService saveService, DesignManager designs, AutomationChanged @event,
FixedDesignMigrator migrator, DesignFileSystem fileSystem, ItemUnlockManager unlockManager) FixedDesignMigrator migrator, DesignFileSystem fileSystem)
{ {
_jobs = jobs; _jobs = jobs;
_actors = actors; _actors = actors;
_saveService = saveService; _saveService = saveService;
_designs = designs; _designs = designs;
_event = @event; _event = @event;
_unlockManager = unlockManager;
Load(); Load();
migrator.ConsumeMigratedData(_actors, fileSystem, this); migrator.ConsumeMigratedData(_actors, fileSystem, this);
} }
@ -64,13 +62,13 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
public void AddDesignSet(string name, ActorIdentifier identifier) public void AddDesignSet(string name, ActorIdentifier identifier)
{ {
if (!IdentifierValid(identifier) || name.Length == 0) if (!IdentifierValid(identifier, out var group) || name.Length == 0)
return; return;
var newSet = new AutoDesignSet(name, identifier.CreatePermanent()) { Enabled = false }; var newSet = new AutoDesignSet(name, group) { Enabled = false };
_data.Add(newSet); _data.Add(newSet);
Save(); Save();
Glamourer.Log.Debug($"Created new design set for {newSet.Identifier.Incognito(null)}."); Glamourer.Log.Debug($"Created new design set for {newSet.Identifiers[0].Incognito(null)}.");
_event.Invoke(AutomationChanged.Type.AddedSet, newSet, (_data.Count - 1, name)); _event.Invoke(AutomationChanged.Type.AddedSet, newSet, (_data.Count - 1, name));
} }
@ -90,12 +88,12 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
name += " (Duplicate)"; name += " (Duplicate)";
} }
var newSet = new AutoDesignSet(name, set.Identifier) { Enabled = false }; var newSet = new AutoDesignSet(name, set.Identifiers) { Enabled = false };
newSet.Designs.AddRange(set.Designs.Select(d => d.Clone())); newSet.Designs.AddRange(set.Designs.Select(d => d.Clone()));
_data.Add(newSet); _data.Add(newSet);
Save(); Save();
Glamourer.Log.Debug( Glamourer.Log.Debug(
$"Duplicated new design set for {newSet.Identifier.Incognito(null)} with {newSet.Designs.Count} auto designs from existing set."); $"Duplicated new design set for {newSet.Identifiers[0].Incognito(null)} with {newSet.Designs.Count} auto designs from existing set.");
_event.Invoke(AutomationChanged.Type.AddedSet, newSet, (_data.Count - 1, name)); _event.Invoke(AutomationChanged.Type.AddedSet, newSet, (_data.Count - 1, name));
} }
@ -108,7 +106,8 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
if (set.Enabled) if (set.Enabled)
{ {
set.Enabled = false; set.Enabled = false;
_enabled.Remove(set.Identifier); foreach (var id in set.Identifiers)
_enabled.Remove(id);
} }
_data.RemoveAt(whichSet); _data.RemoveAt(whichSet);
@ -146,26 +145,33 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
public void ChangeIdentifier(int whichSet, ActorIdentifier to) public void ChangeIdentifier(int whichSet, ActorIdentifier to)
{ {
if (whichSet >= _data.Count || whichSet < 0 || !IdentifierValid(to)) if (whichSet >= _data.Count || whichSet < 0 || !IdentifierValid(to, out var group))
return; return;
var set = _data[whichSet]; var set = _data[whichSet];
if (set.Identifier == to) if (set.Identifiers.Any(id => id == to))
return; return;
var old = set.Identifier; var old = set.Identifiers;
set.Identifier = to.CreatePermanent(); set.Identifiers = group;
AutoDesignSet? oldEnabled = null; AutoDesignSet? oldEnabled = null;
if (set.Enabled) if (set.Enabled)
{ {
_enabled.Remove(old); foreach (var id in old)
_enabled.Remove(id);
if (_enabled.Remove(to, out oldEnabled)) if (_enabled.Remove(to, out oldEnabled))
{
foreach (var id in oldEnabled.Identifiers)
_enabled.Remove(id);
oldEnabled.Enabled = false; oldEnabled.Enabled = false;
_enabled.Add(set.Identifier, set); }
foreach (var id in group)
_enabled.Add(id, set);
} }
Save(); Save();
Glamourer.Log.Debug($"Changed Identifier of design set {whichSet + 1} from {old.Incognito(null)} to {to.Incognito(null)}."); Glamourer.Log.Debug($"Changed Identifier of design set {whichSet + 1} from {old[0].Incognito(null)} to {to.Incognito(null)}.");
_event.Invoke(AutomationChanged.Type.ChangeIdentifier, set, (old, to, oldEnabled)); _event.Invoke(AutomationChanged.Type.ChangeIdentifier, set, (old, to, oldEnabled));
} }
@ -182,13 +188,20 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
AutoDesignSet? oldEnabled = null; AutoDesignSet? oldEnabled = null;
if (value) if (value)
{ {
if (_enabled.Remove(set.Identifier, out oldEnabled)) if (_enabled.Remove(set.Identifiers[0], out oldEnabled))
{
foreach (var id in oldEnabled.Identifiers)
_enabled.Remove(id);
oldEnabled.Enabled = false; oldEnabled.Enabled = false;
_enabled.Add(set.Identifier, set); }
foreach (var id in set.Identifiers)
_enabled.Add(id, set);
} }
else else if (_enabled.Remove(set.Identifiers[0], out oldEnabled))
{ {
_enabled.Remove(set.Identifier, out oldEnabled); foreach (var id in oldEnabled.Identifiers)
_enabled.Remove(id);
} }
Save(); Save();
@ -353,7 +366,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
} }
var id = _actors.AwaitedService.FromJson(obj["Identifier"] as JObject); var id = _actors.AwaitedService.FromJson(obj["Identifier"] as JObject);
if (!IdentifierValid(id)) if (!IdentifierValid(id, out var group))
{ {
Glamourer.Chat.NotificationMessage("Skipped loading Automation Set: Invalid Identifier.", "Warning", NotificationType.Warning); Glamourer.Chat.NotificationMessage("Skipped loading Automation Set: Invalid Identifier.", "Warning", NotificationType.Warning);
continue; continue;
@ -365,8 +378,13 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
}; };
if (set.Enabled) if (set.Enabled)
if (!_enabled.TryAdd(set.Identifier, set)) {
if (_enabled.TryAdd(group[0], set))
foreach (var id2 in group.Skip(1))
_enabled[id2] = set;
else
set.Enabled = false; set.Enabled = false;
}
_data.Add(set); _data.Add(set);
@ -377,7 +395,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
{ {
if (designObj is not JObject j) if (designObj is not JObject j)
{ {
Glamourer.Chat.NotificationMessage($"Skipped loading design in Automation Set for {set.Identifier}: Unknown design."); Glamourer.Chat.NotificationMessage($"Skipped loading design in Automation Set for {id.Incognito(null)}: Unknown design.");
continue; continue;
} }
@ -442,16 +460,57 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
private void Save() private void Save()
=> _saveService.DelaySave(this); => _saveService.DelaySave(this);
private static bool IdentifierValid(ActorIdentifier identifier) private bool IdentifierValid(ActorIdentifier identifier, out ActorIdentifier[] group)
{ {
if (!identifier.IsValid) var validType = identifier.Type switch
return false;
return identifier.Type switch
{ {
IdentifierType.Player => true, IdentifierType.Player => true,
IdentifierType.Retainer => true, IdentifierType.Retainer => true,
IdentifierType.Npc => true,
_ => false, _ => false,
}; };
if (!validType)
{
group = Array.Empty<ActorIdentifier>();
return false;
}
group = GetGroup(identifier);
return group.Length > 0;
}
private ActorIdentifier[] GetGroup(ActorIdentifier identifier)
{
if (!identifier.IsValid)
return Array.Empty<ActorIdentifier>();
static ActorIdentifier[] CreateNpcs(ActorManager manager, ActorIdentifier identifier)
{
var name = manager.Data.ToName(identifier.Kind, identifier.DataId);
var table = identifier.Kind switch
{
ObjectKind.BattleNpc => manager.Data.BNpcs,
ObjectKind.EventNpc => manager.Data.ENpcs,
_ => throw new NotImplementedException(),
};
return table.Where(kvp => kvp.Value == name)
.Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld, identifier.Kind,
kvp.Key)).ToArray();
}
return identifier.Type switch
{
IdentifierType.Player => new[]
{
identifier.CreatePermanent(),
},
IdentifierType.Retainer => new[]
{
identifier.CreatePermanent(),
},
IdentifierType.Npc => CreateNpcs(_actors.AwaitedService, identifier),
_ => Array.Empty<ActorIdentifier>(),
};
} }
} }

View file

@ -8,9 +8,9 @@ public class AutoDesignSet
{ {
public readonly List<AutoDesign> Designs; public readonly List<AutoDesign> Designs;
public string Name; public string Name;
public ActorIdentifier Identifier; public ActorIdentifier[] Identifiers;
public bool Enabled; public bool Enabled;
public JObject Serialize() public JObject Serialize()
{ {
@ -21,20 +21,20 @@ public class AutoDesignSet
return new JObject() return new JObject()
{ {
["Name"] = Name, ["Name"] = Name,
["Identifier"] = Identifier.ToJson(), ["Identifier"] = Identifiers[0].ToJson(),
["Enabled"] = Enabled, ["Enabled"] = Enabled,
["Designs"] = list, ["Designs"] = list,
}; };
} }
public AutoDesignSet(string name, ActorIdentifier identifier) public AutoDesignSet(string name, params ActorIdentifier[] identifiers)
: this(name, identifier, new List<AutoDesign>()) : this(name, identifiers, new List<AutoDesign>())
{ } { }
public AutoDesignSet(string name, ActorIdentifier identifier, List<AutoDesign> designs) public AutoDesignSet(string name, ActorIdentifier[] identifiers, List<AutoDesign> designs)
{ {
Name = name; Name = name;
Identifier = identifier; Identifiers = identifiers;
Designs = designs; Designs = designs;
} }
} }

View file

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Numerics;
using Dalamud.Data; using Dalamud.Data;
using Dalamud.Interface; using Dalamud.Interface;
using Glamourer.Designs; using Glamourer.Designs;
@ -24,16 +25,17 @@ public class EquipmentDrawer
private readonly ItemCombo[] _itemCombo; private readonly ItemCombo[] _itemCombo;
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo; private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
private readonly CodeService _codes; private readonly CodeService _codes;
private readonly TextureService _textures;
public EquipmentDrawer(DataManager gameData, ItemManager items, CodeService codes, TextureService textures)
public EquipmentDrawer(DataManager gameData, ItemManager items, CodeService codes)
{ {
_items = items; _items = items;
_codes = codes; _codes = codes;
_textures = textures;
_stainData = items.Stains; _stainData = items.Stains;
_stainCombo = new FilterComboColors(140, _stainCombo = new FilterComboColors(140,
_stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false)))); _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)).ToArray(); _itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, textures)).ToArray();
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2); _weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
foreach (var type in Enum.GetValues<FullEquipType>()) foreach (var type in Enum.GetValues<FullEquipType>())
{ {
@ -46,6 +48,15 @@ public class EquipmentDrawer
_weaponCombo.Add(FullEquipType.Unknown, new WeaponCombo(items, FullEquipType.Unknown)); _weaponCombo.Add(FullEquipType.Unknown, new WeaponCombo(items, FullEquipType.Unknown));
} }
private Vector2 _iconSize;
private float _comboLength;
public void Prepare()
{
_iconSize = new Vector2(2 * ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y);
_comboLength = 320 * ImGuiHelpers.GlobalScale;
}
private string VerifyRestrictedGear(EquipItem gear, EquipSlot slot, Gender gender, Race race) private string VerifyRestrictedGear(EquipItem gear, EquipSlot slot, Gender gender, Race race)
{ {
if (slot.IsAccessory()) if (slot.IsAccessory())
@ -61,12 +72,20 @@ public class EquipmentDrawer
public bool DrawArmor(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown, Race race = Race.Unknown) public bool DrawArmor(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown, Race race = Race.Unknown)
{ {
Debug.Assert(slot.IsEquipment() || slot.IsAccessory(), $"Called {nameof(DrawArmor)} on {slot}."); Debug.Assert(slot.IsEquipment() || slot.IsAccessory(), $"Called {nameof(DrawArmor)} on {slot}.");
if (_codes.EnabledArtisan) if (_codes.EnabledArtisan)
return DrawArmorArtisan(current, slot, out armor, gender, race); return DrawArmorArtisan(current, slot, out armor, gender, race);
current.DrawIcon(_textures, _iconSize);
ImGui.SameLine();
using var group = ImRaii.Group();
var combo = _itemCombo[slot.ToIndex()]; var combo = _itemCombo[slot.ToIndex()];
armor = current; armor = current;
var change = combo.Draw(VerifyRestrictedGear(armor, slot, gender, race), armor.ItemId, 320 * ImGuiHelpers.GlobalScale); var change = combo.Draw(VerifyRestrictedGear(armor, slot, gender, race), armor.ItemId, _comboLength);
if (change)
armor = combo.CurrentSelection;
if (armor.ModelId.Value != 0) if (armor.ModelId.Value != 0)
{ {
ImGuiUtil.HoverTooltip("Right-click to clear."); ImGuiUtil.HoverTooltip("Right-click to clear.");
@ -75,95 +94,30 @@ public class EquipmentDrawer
change = true; change = true;
armor = ItemManager.NothingItem(slot); armor = ItemManager.NothingItem(slot);
} }
else if (change)
{
armor = combo.CurrentSelection;
}
}
else if (change)
{
armor = combo.CurrentSelection;
} }
return change; return change;
} }
public bool DrawArmorArtisan(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown,
Race race = Race.Unknown)
{
using var id = ImRaii.PushId((int)slot);
int setId = current.ModelId.Value;
int variant = current.Variant;
var ret = false;
armor = current;
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("##setId", ref setId, 0, 0))
{
var newSetId = (SetId)Math.Clamp(setId, 0, ushort.MaxValue);
if (newSetId.Value != current.ModelId.Value)
{
armor = _items.Identify(slot, newSetId, current.Variant);
ret = true;
}
}
ImGui.SameLine();
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("##variant", ref variant, 0, 0))
{
var newVariant = (byte)Math.Clamp(variant, 0, byte.MaxValue);
if (newVariant != current.Variant)
{
armor = _items.Identify(slot, current.ModelId, newVariant);
ret = true;
}
}
return ret;
}
public bool DrawStain(StainId current, EquipSlot slot, out StainId ret) public bool DrawStain(StainId current, EquipSlot slot, out StainId ret)
{ {
if (_codes.EnabledArtisan) if (_codes.EnabledArtisan)
return DrawStainArtisan(current, slot, out ret); return DrawStainArtisan(current, slot, out ret);
var found = _stainData.TryGetValue(current, out var stain); var found = _stainData.TryGetValue(current, out var stain);
var change = _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found); var change = _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, _comboLength);
ret = current;
if (change && _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain))
ret = stain.RowIndex;
ImGuiUtil.HoverTooltip("Right-click to clear."); ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{ {
stain = Stain.None; ret = Stain.None.RowIndex;
ret = stain.RowIndex; change = true;
return true;
} }
if (change && _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain)) return change;
{
ret = stain.RowIndex;
return true;
}
ret = current;
return false;
}
public bool DrawStainArtisan(StainId current, EquipSlot slot, out StainId stain)
{
using var id = ImRaii.PushId((int)slot);
int stainId = current.Value;
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("##stain", ref stainId, 0, 0))
{
var newStainId = (StainId)Math.Clamp(stainId, 0, byte.MaxValue);
if (newStainId != current)
{
stain = newStainId;
return true;
}
}
stain = current;
return false;
} }
public bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon) public bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon)
@ -191,7 +145,9 @@ public class EquipmentDrawer
var change = combo.Draw(weapon.Name, weapon.ItemId, 320 * ImGuiHelpers.GlobalScale); var change = combo.Draw(weapon.Name, weapon.ItemId, 320 * ImGuiHelpers.GlobalScale);
if (change) if (change)
{
weapon = combo.CurrentSelection; weapon = combo.CurrentSelection;
}
else if (!offType.IsOffhandType() && weapon.ModelId.Value != 0) else if (!offType.IsOffhandType() && weapon.ModelId.Value != 0)
{ {
ImGuiUtil.HoverTooltip("Right-click to clear."); ImGuiUtil.HoverTooltip("Right-click to clear.");
@ -229,4 +185,59 @@ public class EquipmentDrawer
public bool DrawWetness(bool current, out bool on) public bool DrawWetness(bool current, out bool on)
=> DrawCheckbox("##wetness", current, out on); => DrawCheckbox("##wetness", current, out on);
/// <summary> Draw an input for armor that can set arbitrary values instead of choosing items. </summary>
private bool DrawArmorArtisan(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown,
Race race = Race.Unknown)
{
using var id = ImRaii.PushId((int)slot);
int setId = current.ModelId.Value;
int variant = current.Variant;
var ret = false;
armor = current;
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("##setId", ref setId, 0, 0))
{
var newSetId = (SetId)Math.Clamp(setId, 0, ushort.MaxValue);
if (newSetId.Value != current.ModelId.Value)
{
armor = _items.Identify(slot, newSetId, current.Variant);
ret = true;
}
}
ImGui.SameLine();
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("##variant", ref variant, 0, 0))
{
var newVariant = (byte)Math.Clamp(variant, 0, byte.MaxValue);
if (newVariant != current.Variant)
{
armor = _items.Identify(slot, current.ModelId, newVariant);
ret = true;
}
}
return ret;
}
/// <summary> Draw an input for stain that can set arbitrary values instead of choosing valid stains. </summary>
private bool DrawStainArtisan(StainId current, EquipSlot slot, out StainId stain)
{
using var id = ImRaii.PushId((int)slot);
int stainId = current.Value;
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("##stain", ref stainId, 0, 0))
{
var newStainId = (StainId)Math.Clamp(stainId, 0, byte.MaxValue);
if (newStainId != current)
{
stain = newStainId;
return true;
}
}
stain = current;
return false;
}
} }

View file

@ -15,12 +15,15 @@ namespace Glamourer.Gui.Equipment;
public sealed class ItemCombo : FilterComboCache<EquipItem> public sealed class ItemCombo : FilterComboCache<EquipItem>
{ {
private readonly TextureService _textures;
public readonly string Label; public readonly string Label;
private uint _currentItem; private uint _currentItem;
public ItemCombo(DataManager gameData, ItemManager items, EquipSlot slot) public ItemCombo(DataManager gameData, ItemManager items, EquipSlot slot, TextureService textures)
: base(() => GetItems(items, slot)) : base(() => GetItems(items, slot))
{ {
_textures = textures;
Label = GetLabel(gameData, slot); Label = GetLabel(gameData, slot);
_currentItem = ItemManager.NothingId(slot); _currentItem = ItemManager.NothingId(slot);
} }
@ -40,7 +43,6 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
CurrentSelectionIdx = Items.IndexOf(i => i.ItemId == _currentItem); CurrentSelectionIdx = Items.IndexOf(i => i.ItemId == _currentItem);
CurrentSelection = CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : default; CurrentSelection = CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : default;
return base.UpdateCurrentSelected(CurrentSelectionIdx); return base.UpdateCurrentSelected(CurrentSelectionIdx);
} }
public bool Draw(string previewName, uint previewIdx, float width) public bool Draw(string previewName, uint previewIdx, float width)

View file

@ -130,6 +130,7 @@ public class ActorPanel
if (_customizationDrawer.Draw(_state!.ModelData.Customize, false)) if (_customizationDrawer.Draw(_state!.ModelData.Customize, false))
_stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateChanged.Source.Manual); _stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateChanged.Source.Manual);
_equipmentDrawer.Prepare();
foreach (var slot in EquipSlotExtensions.EqdpSlots) foreach (var slot in EquipSlotExtensions.EqdpSlots)
{ {
var stain = _state.ModelData.Stain(slot); var stain = _state.ModelData.Stain(slot);

View file

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Utility;
using Glamourer.Services;
using ImGuiNET;
using OtterGui.Custom;
using OtterGui.Widgets;
using Penumbra.GameData.Data;
namespace Glamourer.Gui.Tabs.AutomationTab;
public sealed class HumanNpcCombo : FilterComboCache<(string Name, ObjectKind Kind, uint[] Ids)>
{
private readonly string _label;
public HumanNpcCombo(string label, IdentifierService service, HumanModelList humans)
: base(() => CreateList(service, humans))
=> _label = label;
protected override string ToString((string Name, ObjectKind Kind, uint[] Ids) obj)
=> obj.Name;
protected override bool DrawSelectable(int globalIdx, bool selected)
{
var (name, kind, ids) = Items[globalIdx];
if (globalIdx > 0 && Items[globalIdx - 1].Name == name || globalIdx + 1 < Items.Count && Items[globalIdx + 1].Name == name)
name = $"{name} ({kind.ToName()})";
var ret = ImGui.Selectable(name, selected);
if (ImGui.IsItemHovered())
ImGui.SetTooltip(string.Join('\n', ids.Select(i => i.ToString())));
return ret;
}
public bool Draw(float width)
=> Draw(_label, CurrentSelection.Name, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
/// <summary> Compare strings in a way that letters and numbers are sorted before any special symbols. </summary>
private class NameComparer : IComparer<(string, ObjectKind)>
{
public int Compare((string, ObjectKind) x, (string, ObjectKind) y)
{
if (x.Item1.IsNullOrWhitespace() || y.Item1.IsNullOrWhitespace())
return StringComparer.OrdinalIgnoreCase.Compare(x.Item1, y.Item1);
var comp = (char.IsAsciiLetterOrDigit(x.Item1[0]), char.IsAsciiLetterOrDigit(y.Item1[0])) switch
{
(true, false) => -1,
(false, true) => 1,
_ => StringComparer.OrdinalIgnoreCase.Compare(x.Item1, y.Item1),
};
if (comp != 0)
return comp;
return Comparer<ObjectKind>.Default.Compare(x.Item2, y.Item2);
}
}
private static IReadOnlyList<(string Name, ObjectKind Kind, uint[] Ids)> CreateList(IdentifierService service, HumanModelList humans)
{
var ret = new List<(string Name, ObjectKind Kind, uint Id)>(1024);
for (var modelChara = 0u; modelChara < service.AwaitedService.NumModelChara; ++modelChara)
{
if (!humans.IsHuman(modelChara))
continue;
var list = service.AwaitedService.ModelCharaNames(modelChara);
if (list.Count == 0)
continue;
foreach (var (name, kind, id) in list.Where(t => !t.Name.IsNullOrWhitespace()))
{
switch (kind)
{
case ObjectKind.BattleNpc:
var nameIds = service.AwaitedService.GetBnpcNames(id);
ret.AddRange(nameIds.Select(nameId => (name, kind, nameId)));
break;
case ObjectKind.EventNpc:
ret.Add((name, kind, id));
break;
}
}
}
return ret.GroupBy(t => (t.Name, t.Kind)).OrderBy(g => g.Key, Comparer)
.Select(g => (g.Key.Name, g.Key.Kind, g.Select(g => g.Id).ToArray())).ToList();
}
private static readonly NameComparer Comparer = new();
}

View file

@ -0,0 +1,70 @@
using Dalamud.Game.ClientState.Objects.Enums;
using Glamourer.Services;
using ImGuiNET;
using OtterGui.Custom;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Data;
using Penumbra.String;
namespace Glamourer.Gui.Tabs.AutomationTab;
public class IdentifierDrawer
{
private readonly WorldCombo _worldCombo;
private readonly HumanNpcCombo _humanNpcCombo;
private readonly ActorService _actors;
private string _characterName = string.Empty;
public ActorIdentifier NpcIdentifier { get; private set; } = ActorIdentifier.Invalid;
public ActorIdentifier PlayerIdentifier { get; private set; } = ActorIdentifier.Invalid;
public ActorIdentifier RetainerIdentifier { get; private set; } = ActorIdentifier.Invalid;
public IdentifierDrawer(ActorService actors, IdentifierService identifier, HumanModelList humans)
{
_actors = actors;
_worldCombo = new WorldCombo(actors.AwaitedService.Data.Worlds);
_humanNpcCombo = new HumanNpcCombo("Human Event NPCs", identifier, humans);
}
public void DrawName(float width)
{
ImGui.SetNextItemWidth(width);
if (ImGui.InputTextWithHint("##Name", "Character Name...", ref _characterName, 32))
UpdateIdentifiers();
}
public void DrawWorld(float width)
{
if (_worldCombo.Draw(width))
UpdateIdentifiers();
}
public void DrawNpcs(float width)
{
if (_humanNpcCombo.Draw(width))
UpdateIdentifiers();
}
public bool CanSetPlayer
=> PlayerIdentifier.IsValid;
public bool CanSetRetainer
=> RetainerIdentifier.IsValid;
public bool CanSetNpc
=> NpcIdentifier.IsValid;
private void UpdateIdentifiers()
{
if (ByteString.FromString(_characterName, out var byteName))
{
PlayerIdentifier = _actors.AwaitedService.CreatePlayer(byteName, _worldCombo.CurrentSelection.Key);
RetainerIdentifier = _actors.AwaitedService.CreateRetainer(byteName, ActorIdentifier.RetainerType.Both);
}
NpcIdentifier = _humanNpcCombo.CurrentSelection.Kind is ObjectKind.EventNpc or ObjectKind.BattleNpc
? _actors.AwaitedService.CreateNpc(_humanNpcCombo.CurrentSelection.Kind, _humanNpcCombo.CurrentSelection.Ids[0])
: ActorIdentifier.Invalid;
}
}

View file

@ -1,5 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Text; using System.Text;
@ -12,12 +11,12 @@ using Glamourer.Services;
using Glamourer.Structs; using Glamourer.Structs;
using Glamourer.Unlocks; using Glamourer.Unlocks;
using ImGuiNET; using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using OtterGui.Widgets; using OtterGui.Widgets;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Action = System.Action; using Action = System.Action;
using CustomizeIndex = Glamourer.Customization.CustomizeIndex;
namespace Glamourer.Gui.Tabs.AutomationTab; namespace Glamourer.Gui.Tabs.AutomationTab;
@ -29,8 +28,9 @@ public class SetPanel
private readonly CustomizeUnlockManager _customizeUnlocks; private readonly CustomizeUnlockManager _customizeUnlocks;
private readonly CustomizationService _customizations; private readonly CustomizationService _customizations;
private readonly DesignCombo _designCombo; private readonly DesignCombo _designCombo;
private readonly JobGroupCombo _jobGroupCombo; private readonly JobGroupCombo _jobGroupCombo;
private readonly IdentifierDrawer _identifierDrawer;
private string? _tempName; private string? _tempName;
private int _dragIndex = -1; private int _dragIndex = -1;
@ -38,13 +38,14 @@ public class SetPanel
private Action? _endAction; private Action? _endAction;
public SetPanel(SetSelector selector, AutoDesignManager manager, DesignManager designs, JobService jobs, ItemUnlockManager itemUnlocks, public SetPanel(SetSelector selector, AutoDesignManager manager, DesignManager designs, JobService jobs, ItemUnlockManager itemUnlocks,
CustomizeUnlockManager customizeUnlocks, CustomizationService customizations) CustomizeUnlockManager customizeUnlocks, CustomizationService customizations, IdentifierDrawer identifierDrawer)
{ {
_selector = selector; _selector = selector;
_manager = manager; _manager = manager;
_itemUnlocks = itemUnlocks; _itemUnlocks = itemUnlocks;
_customizeUnlocks = customizeUnlocks; _customizeUnlocks = customizeUnlocks;
_customizations = customizations; _customizations = customizations;
_identifierDrawer = identifierDrawer;
_designCombo = new DesignCombo(_manager, designs); _designCombo = new DesignCombo(_manager, designs);
_jobGroupCombo = new JobGroupCombo(manager, jobs); _jobGroupCombo = new JobGroupCombo(manager, jobs);
} }
@ -101,6 +102,9 @@ public class SetPanel
if (ImGui.Checkbox("Enabled", ref enabled)) if (ImGui.Checkbox("Enabled", ref enabled))
_manager.SetState(_selector.SelectionIndex, enabled); _manager.SetState(_selector.SelectionIndex, enabled);
ImGui.Separator();
DrawIdentifierSelection(_selector.SelectionIndex);
DrawDesignTable(); DrawDesignTable();
} }
@ -201,7 +205,10 @@ public class SetPanel
sb.Clear(); sb.Clear();
var sb2 = new StringBuilder(); var sb2 = new StringBuilder();
var customize = design.Design.DesignData.Customize; var customize = design.Design.DesignData.Customize;
var set = _customizations.AwaitedService.GetList(customize.Clan, customize.Gender); if (!design.Design.DesignData.IsHuman)
sb.AppendLine("The base model id can not be changed automatically to something non-human.");
var set = _customizations.AwaitedService.GetList(customize.Clan, customize.Gender);
foreach (var type in CustomizationExtensions.All) foreach (var type in CustomizationExtensions.All)
{ {
var flag = type.ToFlag(); var flag = type.ToFlag();
@ -268,6 +275,21 @@ public class SetPanel
_manager.ChangeApplicationType(set, autoDesignIndex, newType); _manager.ChangeApplicationType(set, autoDesignIndex, newType);
} }
private void DrawIdentifierSelection(int setIndex)
{
using var id = ImRaii.PushId("Identifiers");
_identifierDrawer.DrawWorld(200);
_identifierDrawer.DrawName(300);
_identifierDrawer.DrawNpcs(300);
if (ImGuiUtil.DrawDisabledButton("Set to Retainer", new Vector2(100, 0), string.Empty, !_identifierDrawer.CanSetRetainer))
_manager.ChangeIdentifier(setIndex, _identifierDrawer.RetainerIdentifier);
ImGui.SameLine();
if (ImGuiUtil.DrawDisabledButton("Set to Character", new Vector2(100, 0), string.Empty, !_identifierDrawer.CanSetPlayer))
_manager.ChangeIdentifier(setIndex, _identifierDrawer.PlayerIdentifier);
ImGui.SameLine();
if (ImGuiUtil.DrawDisabledButton("Set to Npc", new Vector2(100, 0), string.Empty, !_identifierDrawer.CanSetNpc))
_manager.ChangeIdentifier(setIndex, _identifierDrawer.NpcIdentifier);
}
private static readonly IReadOnlyList<(AutoDesign.Type, string)> Types = new[] private static readonly IReadOnlyList<(AutoDesign.Type, string)> Types = new[]

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Numerics; using System.Numerics;
using Dalamud.Interface; using Dalamud.Interface;
using Glamourer.Automation; using Glamourer.Automation;
@ -118,7 +119,7 @@ public class SetSelector : IDisposable
_list.Clear(); _list.Clear();
foreach (var set in _manager) foreach (var set in _manager)
{ {
var id = set.Identifier.ToString(); var id = set.Identifiers[0].ToString();
if (CheckFilters(set, id)) if (CheckFilters(set, id))
_list.Add(set); _list.Add(set);
} }
@ -195,11 +196,11 @@ public class SetSelector : IDisposable
DrawDragDrop(set, index); DrawDragDrop(set, index);
var text = set.Identifier.ToString(); var text = set.Identifiers[0].ToString();
if (IncognitoMode) if (IncognitoMode)
text = set.Identifier.Incognito(text); text = set.Identifiers[0].Incognito(text);
var textSize = ImGui.CalcTextSize(text); var textSize = ImGui.CalcTextSize(text);
var textColor = _objects.ContainsKey(set.Identifier) ? ColorId.AutomationActorAvailable : ColorId.AutomationActorUnavailable; var textColor = set.Identifiers.Any(_objects.ContainsKey) ? ColorId.AutomationActorAvailable : ColorId.AutomationActorUnavailable;
ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - textSize.X, ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - textSize.X,
ImGui.GetCursorPosY() - ImGui.GetTextLineHeightWithSpacing())); ImGui.GetCursorPosY() - ImGui.GetTextLineHeightWithSpacing()));
ImGuiUtil.TextColored(textColor.Value(), text); ImGuiUtil.TextColored(textColor.Value(), text);

View file

@ -1304,7 +1304,7 @@ public unsafe class DebugTab : ITab
ImGuiUtil.DrawTableColumn(set.Enabled.ToString()); ImGuiUtil.DrawTableColumn(set.Enabled.ToString());
ImGuiUtil.DrawTableColumn("Actor"); ImGuiUtil.DrawTableColumn("Actor");
ImGuiUtil.DrawTableColumn(set.Identifier.ToString()); ImGuiUtil.DrawTableColumn(set.Identifiers[0].ToString());
foreach (var (design, designIdx) in set.Designs.WithIndex()) foreach (var (design, designIdx) in set.Designs.WithIndex())
{ {

View file

@ -127,6 +127,7 @@ public class DesignPanel
if (!ImGui.CollapsingHeader("Equipment")) if (!ImGui.CollapsingHeader("Equipment"))
return; return;
_equipmentDrawer.Prepare();
foreach (var slot in EquipSlotExtensions.EqdpSlots) foreach (var slot in EquipSlotExtensions.EqdpSlots)
{ {
var stain = _selector.Selected!.DesignData.Stain(slot); var stain = _selector.Selected!.DesignData.Stain(slot);

View file

@ -21,7 +21,7 @@ public class UnlockOverview
private readonly CustomizationService _customizations; private readonly CustomizationService _customizations;
private readonly CustomizeUnlockManager _customizeUnlocks; private readonly CustomizeUnlockManager _customizeUnlocks;
private readonly PenumbraChangedItemTooltip _tooltip; private readonly PenumbraChangedItemTooltip _tooltip;
private readonly TextureCache _textureCache; private readonly TextureService _textures;
private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f); private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f);
@ -67,14 +67,14 @@ public class UnlockOverview
} }
public UnlockOverview(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks, public UnlockOverview(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks,
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureCache textureCache) CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureService textures)
{ {
_items = items; _items = items;
_customizations = customizations; _customizations = customizations;
_itemUnlocks = itemUnlocks; _itemUnlocks = itemUnlocks;
_customizeUnlocks = customizeUnlocks; _customizeUnlocks = customizeUnlocks;
_tooltip = tooltip; _tooltip = tooltip;
_textureCache = textureCache; _textures = textures;
} }
public void Draw() public void Draw()
@ -154,7 +154,7 @@ public class UnlockOverview
void DrawItem(EquipItem item) void DrawItem(EquipItem item)
{ {
var unlocked = _itemUnlocks.IsUnlocked(item.ItemId, out var time); var unlocked = _itemUnlocks.IsUnlocked(item.ItemId, out var time);
var iconHandle = _textureCache.LoadIcon(item.IconId); var iconHandle = _textures.LoadIcon(item.IconId);
if (!iconHandle.HasValue) if (!iconHandle.HasValue)
return; return;

View file

@ -10,7 +10,6 @@ using Glamourer.Structs;
using Glamourer.Unlocks; using Glamourer.Unlocks;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii; using OtterGui.Raii;
using OtterGui.Table; using OtterGui.Table;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
@ -22,10 +21,10 @@ public class UnlockTable : Table<EquipItem>, IDisposable
{ {
private readonly ObjectUnlocked _event; private readonly ObjectUnlocked _event;
public UnlockTable(ItemManager items, TextureCache cache, ItemUnlockManager itemUnlocks, public UnlockTable(ItemManager items, TextureService textures, ItemUnlockManager itemUnlocks,
PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event) PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event)
: base("ItemUnlockTable", new ItemList(items), : base("ItemUnlockTable", new ItemList(items),
new NameColumn(cache, tooltip) { Label = "Item Name..." }, new NameColumn(textures, tooltip) { Label = "Item Name..." },
new SlotColumn() { Label = "Equip Slot" }, new SlotColumn() { Label = "Equip Slot" },
new TypeColumn() { Label = "Item Type..." }, new TypeColumn() { Label = "Item Type..." },
new UnlockDateColumn(itemUnlocks) { Label = "Unlocked" }, new UnlockDateColumn(itemUnlocks) { Label = "Unlocked" },
@ -36,7 +35,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
Sortable = true; Sortable = true;
Flags |= ImGuiTableFlags.Hideable; Flags |= ImGuiTableFlags.Hideable;
_event.Subscribe(OnObjectUnlock, ObjectUnlocked.Priority.UnlockTable); _event.Subscribe(OnObjectUnlock, ObjectUnlocked.Priority.UnlockTable);
cache.Logger = Glamourer.Log; textures.Logger = Glamourer.Log;
} }
public void Dispose() public void Dispose()
@ -44,13 +43,13 @@ public class UnlockTable : Table<EquipItem>, IDisposable
private sealed class NameColumn : ColumnString<EquipItem> private sealed class NameColumn : ColumnString<EquipItem>
{ {
private readonly TextureCache _textures; private readonly TextureService _textures;
private readonly PenumbraChangedItemTooltip _tooltip; private readonly PenumbraChangedItemTooltip _tooltip;
public override float Width public override float Width
=> 400 * ImGuiHelpers.GlobalScale; => 400 * ImGuiHelpers.GlobalScale;
public NameColumn(TextureCache textures, PenumbraChangedItemTooltip tooltip) public NameColumn(TextureService textures, PenumbraChangedItemTooltip tooltip)
{ {
_textures = textures; _textures = textures;
_tooltip = tooltip; _tooltip = tooltip;

View file

@ -0,0 +1,34 @@
using System.Numerics;
using Dalamud.Interface;
using Glamourer.Services;
using ImGuiNET;
using OtterGui;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui;
public static class UiHelpers
{
public static void DrawIcon(this EquipItem item, TextureService textures, Vector2 size)
{
var isEmpty = item.ModelId.Value == 0;
var (ptr, textureSize, empty) = textures.GetIcon(item);
if (empty)
{
var pos = ImGui.GetCursorScreenPos();
ImGui.GetWindowDrawList().AddRectFilled(pos, pos + size,
ImGui.GetColorU32(isEmpty ? ImGuiCol.FrameBg : ImGuiCol.FrameBgActive), 5 * ImGuiHelpers.GlobalScale);
if (ptr != nint.Zero)
ImGui.Image(ptr, size, Vector2.Zero, Vector2.One,
isEmpty ? new Vector4(0.1f, 0.1f, 0.1f, 0.5f) : new Vector4(0.3f, 0.3f, 0.3f, 0.8f));
else
ImGui.Dummy(size);
}
else
{
ImGuiUtil.HoverIcon(ptr, textureSize, size);
}
}
}

View file

@ -56,7 +56,7 @@ public static class ServiceManager
.AddSingleton<CodeService>() .AddSingleton<CodeService>()
.AddSingleton<ConfigMigrationService>() .AddSingleton<ConfigMigrationService>()
.AddSingleton<Configuration>() .AddSingleton<Configuration>()
.AddSingleton<TextureCache>(); .AddSingleton<TextureService>();
private static IServiceCollection AddEvents(this IServiceCollection services) private static IServiceCollection AddEvents(this IServiceCollection services)
=> services.AddSingleton<VisorStateChanged>() => services.AddSingleton<VisorStateChanged>()
@ -126,7 +126,8 @@ public static class ServiceManager
.AddSingleton<PenumbraChangedItemTooltip>() .AddSingleton<PenumbraChangedItemTooltip>()
.AddSingleton<AutomationTab>() .AddSingleton<AutomationTab>()
.AddSingleton<SetSelector>() .AddSingleton<SetSelector>()
.AddSingleton<SetPanel>(); .AddSingleton<SetPanel>()
.AddSingleton<IdentifierDrawer>();
private static IServiceCollection AddApi(this IServiceCollection services) private static IServiceCollection AddApi(this IServiceCollection services)
=> services.AddSingleton<CommandService>() => services.AddSingleton<CommandService>()

View file

@ -0,0 +1,71 @@
using System;
using System.Linq;
using Dalamud.Data;
using System.Numerics;
using Dalamud.Game;
using Dalamud.Interface;
using ImGuiScene;
using OtterGui.Classes;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Services;
public sealed class TextureService : TextureCache, IDisposable
{
public TextureService(Framework framework, UiBuilder uiBuilder, DataManager dataManager)
: base(framework, uiBuilder, dataManager)
=> _slotIcons = CreateSlotIcons(uiBuilder);
private readonly TextureWrap?[] _slotIcons;
public (nint, Vector2, bool) GetIcon(EquipItem item)
{
if (item.IconId != 0 && TryLoadIcon(item.IconId, out var ret))
return (ret.Value.Texture, ret.Value.Dimensions, false);
var idx = item.Type.ToSlot().ToIndex();
return idx < 12 && _slotIcons[idx] != null
? (_slotIcons[idx]!.ImGuiHandle, new Vector2(_slotIcons[idx]!.Width, _slotIcons[idx]!.Height), true)
: (nint.Zero, Vector2.Zero, true);
}
public new void Dispose()
{
base.Dispose();
for (var i = 0; i < _slotIcons.Length; ++i)
{
_slotIcons[i]?.Dispose();
_slotIcons[i] = null;
}
}
private static TextureWrap[] CreateSlotIcons(UiBuilder uiBuilder)
{
var ret = new TextureWrap[12];
using var uldWrapper = uiBuilder.LoadUld("ui/uld/ArmouryBoard.uld");
if (!uldWrapper.Valid)
{
Glamourer.Log.Error($"Could not get empty slot uld.");
return ret;
}
ret[0] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 1)!;
ret[1] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 2)!;
ret[2] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 3)!;
ret[3] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 5)!;
ret[4] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 6)!;
ret[5] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 8)!;
ret[6] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 9)!;
ret[7] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 10)!;
ret[8] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 11)!;
ret[9] = ret[10];
ret[10] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 0)!;
ret[11] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", 7)!;
uldWrapper.Dispose();
return ret;
}
}