mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +01:00
Support human NPCs for identifiers.
This commit is contained in:
parent
a310e01296
commit
b00e6bd98b
17 changed files with 536 additions and 162 deletions
|
|
@ -68,24 +68,27 @@ public class AutoDesignApplier : IDisposable
|
|||
case AutomationChanged.Type.ChangedDesign:
|
||||
case AutomationChanged.Type.ChangedConditions:
|
||||
_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);
|
||||
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))
|
||||
if (_state.GetOrCreate(id1, data.Objects[0], out var state))
|
||||
{
|
||||
Reduce(actor, state, set, false);
|
||||
_state.ReapplyState(actor);
|
||||
Reduce(data.Objects[0], state, set, false);
|
||||
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;
|
||||
CustomizeFlag fixFlags = 0;
|
||||
|
||||
// Skip anything not human.
|
||||
if (!state.ModelData.IsHuman || !design.IsHuman)
|
||||
return;
|
||||
|
||||
// Skip invalid designs entirely.
|
||||
if (_config.SkipInvalidCustomizations
|
||||
&& !_code.EnabledMesmer
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Dalamud.Utility;
|
||||
using Glamourer.Designs;
|
||||
|
|
@ -11,7 +12,6 @@ using Glamourer.Events;
|
|||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Glamourer.Unlocks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Filesystem;
|
||||
|
|
@ -29,7 +29,6 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
private readonly DesignManager _designs;
|
||||
private readonly ActorService _actors;
|
||||
private readonly AutomationChanged _event;
|
||||
private readonly ItemUnlockManager _unlockManager;
|
||||
|
||||
private readonly List<AutoDesignSet> _data = new();
|
||||
private readonly Dictionary<ActorIdentifier, AutoDesignSet> _enabled = new();
|
||||
|
|
@ -38,14 +37,13 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
=> _enabled;
|
||||
|
||||
public AutoDesignManager(JobService jobs, ActorService actors, SaveService saveService, DesignManager designs, AutomationChanged @event,
|
||||
FixedDesignMigrator migrator, DesignFileSystem fileSystem, ItemUnlockManager unlockManager)
|
||||
FixedDesignMigrator migrator, DesignFileSystem fileSystem)
|
||||
{
|
||||
_jobs = jobs;
|
||||
_actors = actors;
|
||||
_saveService = saveService;
|
||||
_designs = designs;
|
||||
_event = @event;
|
||||
_unlockManager = unlockManager;
|
||||
_jobs = jobs;
|
||||
_actors = actors;
|
||||
_saveService = saveService;
|
||||
_designs = designs;
|
||||
_event = @event;
|
||||
Load();
|
||||
migrator.ConsumeMigratedData(_actors, fileSystem, this);
|
||||
}
|
||||
|
|
@ -64,13 +62,13 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
|
||||
public void AddDesignSet(string name, ActorIdentifier identifier)
|
||||
{
|
||||
if (!IdentifierValid(identifier) || name.Length == 0)
|
||||
if (!IdentifierValid(identifier, out var group) || name.Length == 0)
|
||||
return;
|
||||
|
||||
var newSet = new AutoDesignSet(name, identifier.CreatePermanent()) { Enabled = false };
|
||||
var newSet = new AutoDesignSet(name, group) { Enabled = false };
|
||||
_data.Add(newSet);
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
@ -90,12 +88,12 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
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()));
|
||||
_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.");
|
||||
$"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));
|
||||
}
|
||||
|
||||
|
|
@ -108,7 +106,8 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
if (set.Enabled)
|
||||
{
|
||||
set.Enabled = false;
|
||||
_enabled.Remove(set.Identifier);
|
||||
foreach (var id in set.Identifiers)
|
||||
_enabled.Remove(id);
|
||||
}
|
||||
|
||||
_data.RemoveAt(whichSet);
|
||||
|
|
@ -146,26 +145,33 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
|
||||
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;
|
||||
|
||||
var set = _data[whichSet];
|
||||
if (set.Identifier == to)
|
||||
if (set.Identifiers.Any(id => id == to))
|
||||
return;
|
||||
|
||||
var old = set.Identifier;
|
||||
set.Identifier = to.CreatePermanent();
|
||||
var old = set.Identifiers;
|
||||
set.Identifiers = group;
|
||||
AutoDesignSet? oldEnabled = null;
|
||||
if (set.Enabled)
|
||||
{
|
||||
_enabled.Remove(old);
|
||||
foreach (var id in old)
|
||||
_enabled.Remove(id);
|
||||
if (_enabled.Remove(to, out oldEnabled))
|
||||
{
|
||||
foreach (var id in oldEnabled.Identifiers)
|
||||
_enabled.Remove(id);
|
||||
oldEnabled.Enabled = false;
|
||||
_enabled.Add(set.Identifier, set);
|
||||
}
|
||||
|
||||
foreach (var id in group)
|
||||
_enabled.Add(id, set);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
@ -182,13 +188,20 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
AutoDesignSet? oldEnabled = null;
|
||||
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;
|
||||
_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();
|
||||
|
|
@ -353,7 +366,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
}
|
||||
|
||||
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);
|
||||
continue;
|
||||
|
|
@ -365,8 +378,13 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
_data.Add(set);
|
||||
|
||||
|
|
@ -377,7 +395,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -442,16 +460,57 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
|
|||
private void Save()
|
||||
=> _saveService.DelaySave(this);
|
||||
|
||||
private static bool IdentifierValid(ActorIdentifier identifier)
|
||||
private bool IdentifierValid(ActorIdentifier identifier, out ActorIdentifier[] group)
|
||||
{
|
||||
if (!identifier.IsValid)
|
||||
return false;
|
||||
|
||||
return identifier.Type switch
|
||||
var validType = identifier.Type switch
|
||||
{
|
||||
IdentifierType.Player => true,
|
||||
IdentifierType.Retainer => true,
|
||||
IdentifierType.Npc => true,
|
||||
_ => 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>(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ public class AutoDesignSet
|
|||
{
|
||||
public readonly List<AutoDesign> Designs;
|
||||
|
||||
public string Name;
|
||||
public ActorIdentifier Identifier;
|
||||
public bool Enabled;
|
||||
public string Name;
|
||||
public ActorIdentifier[] Identifiers;
|
||||
public bool Enabled;
|
||||
|
||||
public JObject Serialize()
|
||||
{
|
||||
|
|
@ -21,20 +21,20 @@ public class AutoDesignSet
|
|||
return new JObject()
|
||||
{
|
||||
["Name"] = Name,
|
||||
["Identifier"] = Identifier.ToJson(),
|
||||
["Identifier"] = Identifiers[0].ToJson(),
|
||||
["Enabled"] = Enabled,
|
||||
["Designs"] = list,
|
||||
};
|
||||
}
|
||||
|
||||
public AutoDesignSet(string name, ActorIdentifier identifier)
|
||||
: this(name, identifier, new List<AutoDesign>())
|
||||
public AutoDesignSet(string name, params ActorIdentifier[] identifiers)
|
||||
: 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;
|
||||
Identifier = identifier;
|
||||
Designs = designs;
|
||||
Name = name;
|
||||
Identifiers = identifiers;
|
||||
Designs = designs;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Designs;
|
||||
|
|
@ -24,16 +25,17 @@ public class EquipmentDrawer
|
|||
private readonly ItemCombo[] _itemCombo;
|
||||
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
|
||||
private readonly CodeService _codes;
|
||||
private readonly TextureService _textures;
|
||||
|
||||
|
||||
public EquipmentDrawer(DataManager gameData, ItemManager items, CodeService codes)
|
||||
public EquipmentDrawer(DataManager gameData, ItemManager items, CodeService codes, TextureService textures)
|
||||
{
|
||||
_items = items;
|
||||
_codes = codes;
|
||||
_textures = textures;
|
||||
_stainData = items.Stains;
|
||||
_stainCombo = new FilterComboColors(140,
|
||||
_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);
|
||||
foreach (var type in Enum.GetValues<FullEquipType>())
|
||||
{
|
||||
|
|
@ -46,6 +48,15 @@ public class EquipmentDrawer
|
|||
_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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Debug.Assert(slot.IsEquipment() || slot.IsAccessory(), $"Called {nameof(DrawArmor)} on {slot}.");
|
||||
|
||||
if (_codes.EnabledArtisan)
|
||||
return DrawArmorArtisan(current, slot, out armor, gender, race);
|
||||
|
||||
current.DrawIcon(_textures, _iconSize);
|
||||
ImGui.SameLine();
|
||||
using var group = ImRaii.Group();
|
||||
|
||||
var combo = _itemCombo[slot.ToIndex()];
|
||||
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)
|
||||
{
|
||||
ImGuiUtil.HoverTooltip("Right-click to clear.");
|
||||
|
|
@ -75,95 +94,30 @@ public class EquipmentDrawer
|
|||
change = true;
|
||||
armor = ItemManager.NothingItem(slot);
|
||||
}
|
||||
else if (change)
|
||||
{
|
||||
armor = combo.CurrentSelection;
|
||||
}
|
||||
}
|
||||
else if (change)
|
||||
{
|
||||
armor = combo.CurrentSelection;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (_codes.EnabledArtisan)
|
||||
return DrawStainArtisan(current, slot, out ret);
|
||||
|
||||
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.");
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
stain = Stain.None;
|
||||
ret = stain.RowIndex;
|
||||
return true;
|
||||
ret = Stain.None.RowIndex;
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (change && _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain))
|
||||
{
|
||||
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;
|
||||
return change;
|
||||
}
|
||||
|
||||
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);
|
||||
if (change)
|
||||
{
|
||||
weapon = combo.CurrentSelection;
|
||||
}
|
||||
else if (!offType.IsOffhandType() && weapon.ModelId.Value != 0)
|
||||
{
|
||||
ImGuiUtil.HoverTooltip("Right-click to clear.");
|
||||
|
|
@ -229,4 +185,59 @@ public class EquipmentDrawer
|
|||
|
||||
public bool DrawWetness(bool current, out bool 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,15 @@ namespace Glamourer.Gui.Equipment;
|
|||
|
||||
public sealed class ItemCombo : FilterComboCache<EquipItem>
|
||||
{
|
||||
private readonly TextureService _textures;
|
||||
|
||||
public readonly string Label;
|
||||
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))
|
||||
{
|
||||
_textures = textures;
|
||||
Label = GetLabel(gameData, slot);
|
||||
_currentItem = ItemManager.NothingId(slot);
|
||||
}
|
||||
|
|
@ -40,7 +43,6 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
|
|||
CurrentSelectionIdx = Items.IndexOf(i => i.ItemId == _currentItem);
|
||||
CurrentSelection = CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : default;
|
||||
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||
|
||||
}
|
||||
|
||||
public bool Draw(string previewName, uint previewIdx, float width)
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ public class ActorPanel
|
|||
if (_customizationDrawer.Draw(_state!.ModelData.Customize, false))
|
||||
_stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateChanged.Source.Manual);
|
||||
|
||||
_equipmentDrawer.Prepare();
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var stain = _state.ModelData.Stain(slot);
|
||||
|
|
|
|||
95
Glamourer/Gui/Tabs/AutomationTab/HumanNpcCombo.cs
Normal file
95
Glamourer/Gui/Tabs/AutomationTab/HumanNpcCombo.cs
Normal 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();
|
||||
}
|
||||
70
Glamourer/Gui/Tabs/AutomationTab/IdentifierDrawer.cs
Normal file
70
Glamourer/Gui/Tabs/AutomationTab/IdentifierDrawer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
|
@ -12,12 +11,12 @@ using Glamourer.Services;
|
|||
using Glamourer.Structs;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Action = System.Action;
|
||||
using CustomizeIndex = Glamourer.Customization.CustomizeIndex;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
|
|
@ -29,8 +28,9 @@ public class SetPanel
|
|||
private readonly CustomizeUnlockManager _customizeUnlocks;
|
||||
private readonly CustomizationService _customizations;
|
||||
|
||||
private readonly DesignCombo _designCombo;
|
||||
private readonly JobGroupCombo _jobGroupCombo;
|
||||
private readonly DesignCombo _designCombo;
|
||||
private readonly JobGroupCombo _jobGroupCombo;
|
||||
private readonly IdentifierDrawer _identifierDrawer;
|
||||
|
||||
private string? _tempName;
|
||||
private int _dragIndex = -1;
|
||||
|
|
@ -38,13 +38,14 @@ public class SetPanel
|
|||
private Action? _endAction;
|
||||
|
||||
public SetPanel(SetSelector selector, AutoDesignManager manager, DesignManager designs, JobService jobs, ItemUnlockManager itemUnlocks,
|
||||
CustomizeUnlockManager customizeUnlocks, CustomizationService customizations)
|
||||
CustomizeUnlockManager customizeUnlocks, CustomizationService customizations, IdentifierDrawer identifierDrawer)
|
||||
{
|
||||
_selector = selector;
|
||||
_manager = manager;
|
||||
_itemUnlocks = itemUnlocks;
|
||||
_customizeUnlocks = customizeUnlocks;
|
||||
_customizations = customizations;
|
||||
_identifierDrawer = identifierDrawer;
|
||||
_designCombo = new DesignCombo(_manager, designs);
|
||||
_jobGroupCombo = new JobGroupCombo(manager, jobs);
|
||||
}
|
||||
|
|
@ -101,6 +102,9 @@ public class SetPanel
|
|||
if (ImGui.Checkbox("Enabled", ref enabled))
|
||||
_manager.SetState(_selector.SelectionIndex, enabled);
|
||||
|
||||
ImGui.Separator();
|
||||
DrawIdentifierSelection(_selector.SelectionIndex);
|
||||
|
||||
DrawDesignTable();
|
||||
}
|
||||
|
||||
|
|
@ -201,7 +205,10 @@ public class SetPanel
|
|||
sb.Clear();
|
||||
var sb2 = new StringBuilder();
|
||||
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)
|
||||
{
|
||||
var flag = type.ToFlag();
|
||||
|
|
@ -268,6 +275,21 @@ public class SetPanel
|
|||
_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[]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Automation;
|
||||
|
|
@ -118,7 +119,7 @@ public class SetSelector : IDisposable
|
|||
_list.Clear();
|
||||
foreach (var set in _manager)
|
||||
{
|
||||
var id = set.Identifier.ToString();
|
||||
var id = set.Identifiers[0].ToString();
|
||||
if (CheckFilters(set, id))
|
||||
_list.Add(set);
|
||||
}
|
||||
|
|
@ -195,11 +196,11 @@ public class SetSelector : IDisposable
|
|||
|
||||
DrawDragDrop(set, index);
|
||||
|
||||
var text = set.Identifier.ToString();
|
||||
var text = set.Identifiers[0].ToString();
|
||||
if (IncognitoMode)
|
||||
text = set.Identifier.Incognito(text);
|
||||
text = set.Identifiers[0].Incognito(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.GetCursorPosY() - ImGui.GetTextLineHeightWithSpacing()));
|
||||
ImGuiUtil.TextColored(textColor.Value(), text);
|
||||
|
|
|
|||
|
|
@ -1304,7 +1304,7 @@ public unsafe class DebugTab : ITab
|
|||
ImGuiUtil.DrawTableColumn(set.Enabled.ToString());
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Actor");
|
||||
ImGuiUtil.DrawTableColumn(set.Identifier.ToString());
|
||||
ImGuiUtil.DrawTableColumn(set.Identifiers[0].ToString());
|
||||
|
||||
foreach (var (design, designIdx) in set.Designs.WithIndex())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ public class DesignPanel
|
|||
if (!ImGui.CollapsingHeader("Equipment"))
|
||||
return;
|
||||
|
||||
_equipmentDrawer.Prepare();
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var stain = _selector.Selected!.DesignData.Stain(slot);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public class UnlockOverview
|
|||
private readonly CustomizationService _customizations;
|
||||
private readonly CustomizeUnlockManager _customizeUnlocks;
|
||||
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);
|
||||
|
||||
|
|
@ -67,14 +67,14 @@ public class UnlockOverview
|
|||
}
|
||||
|
||||
public UnlockOverview(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks,
|
||||
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureCache textureCache)
|
||||
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureService textures)
|
||||
{
|
||||
_items = items;
|
||||
_customizations = customizations;
|
||||
_itemUnlocks = itemUnlocks;
|
||||
_customizeUnlocks = customizeUnlocks;
|
||||
_tooltip = tooltip;
|
||||
_textureCache = textureCache;
|
||||
_textures = textures;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
|
|
@ -154,7 +154,7 @@ public class UnlockOverview
|
|||
void DrawItem(EquipItem item)
|
||||
{
|
||||
var unlocked = _itemUnlocks.IsUnlocked(item.ItemId, out var time);
|
||||
var iconHandle = _textureCache.LoadIcon(item.IconId);
|
||||
var iconHandle = _textures.LoadIcon(item.IconId);
|
||||
if (!iconHandle.HasValue)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ using Glamourer.Structs;
|
|||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Table;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -22,10 +21,10 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
{
|
||||
private readonly ObjectUnlocked _event;
|
||||
|
||||
public UnlockTable(ItemManager items, TextureCache cache, ItemUnlockManager itemUnlocks,
|
||||
public UnlockTable(ItemManager items, TextureService textures, ItemUnlockManager itemUnlocks,
|
||||
PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event)
|
||||
: 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 TypeColumn() { Label = "Item Type..." },
|
||||
new UnlockDateColumn(itemUnlocks) { Label = "Unlocked" },
|
||||
|
|
@ -36,7 +35,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
Sortable = true;
|
||||
Flags |= ImGuiTableFlags.Hideable;
|
||||
_event.Subscribe(OnObjectUnlock, ObjectUnlocked.Priority.UnlockTable);
|
||||
cache.Logger = Glamourer.Log;
|
||||
textures.Logger = Glamourer.Log;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -44,13 +43,13 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
|
||||
private sealed class NameColumn : ColumnString<EquipItem>
|
||||
{
|
||||
private readonly TextureCache _textures;
|
||||
private readonly TextureService _textures;
|
||||
private readonly PenumbraChangedItemTooltip _tooltip;
|
||||
|
||||
public override float Width
|
||||
=> 400 * ImGuiHelpers.GlobalScale;
|
||||
|
||||
public NameColumn(TextureCache textures, PenumbraChangedItemTooltip tooltip)
|
||||
public NameColumn(TextureService textures, PenumbraChangedItemTooltip tooltip)
|
||||
{
|
||||
_textures = textures;
|
||||
_tooltip = tooltip;
|
||||
|
|
|
|||
34
Glamourer/Gui/UiHelpers.cs
Normal file
34
Glamourer/Gui/UiHelpers.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ public static class ServiceManager
|
|||
.AddSingleton<CodeService>()
|
||||
.AddSingleton<ConfigMigrationService>()
|
||||
.AddSingleton<Configuration>()
|
||||
.AddSingleton<TextureCache>();
|
||||
.AddSingleton<TextureService>();
|
||||
|
||||
private static IServiceCollection AddEvents(this IServiceCollection services)
|
||||
=> services.AddSingleton<VisorStateChanged>()
|
||||
|
|
@ -126,7 +126,8 @@ public static class ServiceManager
|
|||
.AddSingleton<PenumbraChangedItemTooltip>()
|
||||
.AddSingleton<AutomationTab>()
|
||||
.AddSingleton<SetSelector>()
|
||||
.AddSingleton<SetPanel>();
|
||||
.AddSingleton<SetPanel>()
|
||||
.AddSingleton<IdentifierDrawer>();
|
||||
|
||||
private static IServiceCollection AddApi(this IServiceCollection services)
|
||||
=> services.AddSingleton<CommandService>()
|
||||
|
|
|
|||
71
Glamourer/Services/TextureService.cs
Normal file
71
Glamourer/Services/TextureService.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue