This commit is contained in:
Ottermandias 2023-01-31 21:08:56 +01:00
parent e27a194cc6
commit 145b64bb7a
17 changed files with 258 additions and 674 deletions

View file

@ -1,107 +1,17 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Dalamud;
using Dalamud.Data;
using Glamourer.Structs;
using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums;
namespace Glamourer;
public static class GameData
{
private static Dictionary<EquipSlot, List<Item2>>? _itemsBySlot;
private static Dictionary<byte, Job>? _jobs;
private static Dictionary<ushort, JobGroup>? _jobGroups;
public static IReadOnlyDictionary<EquipSlot, List<Item2>> ItemsBySlot(DataManager dataManager)
{
if (_itemsBySlot != null)
return _itemsBySlot;
var sheet = dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets.Item>()!;
Item2 EmptySlot(EquipSlot slot)
=> new(sheet.First(), "Nothing", slot);
static Item2 EmptyNpc(EquipSlot slot)
=> new(new Lumina.Excel.GeneratedSheets.Item() { ModelMain = 9903 }, "Smallclothes (NPC)", slot);
_itemsBySlot = new Dictionary<EquipSlot, List<Item2>>()
{
[EquipSlot.Head] = new(200)
{
EmptySlot(EquipSlot.Head),
EmptyNpc(EquipSlot.Head),
},
[EquipSlot.Body] = new(200)
{
EmptySlot(EquipSlot.Body),
EmptyNpc(EquipSlot.Body),
},
[EquipSlot.Hands] = new(200)
{
EmptySlot(EquipSlot.Hands),
EmptyNpc(EquipSlot.Hands),
},
[EquipSlot.Legs] = new(200)
{
EmptySlot(EquipSlot.Legs),
EmptyNpc(EquipSlot.Legs),
},
[EquipSlot.Feet] = new(200)
{
EmptySlot(EquipSlot.Feet),
EmptyNpc(EquipSlot.Feet),
},
[EquipSlot.MainHand] = new(2000),
[EquipSlot.RFinger] = new(200)
{
EmptySlot(EquipSlot.RFinger),
EmptyNpc(EquipSlot.RFinger),
},
[EquipSlot.Neck] = new(200)
{
EmptySlot(EquipSlot.Neck),
EmptyNpc(EquipSlot.Neck),
},
[EquipSlot.Wrists] = new(200)
{
EmptySlot(EquipSlot.Wrists),
EmptyNpc(EquipSlot.Wrists),
},
[EquipSlot.Ears] = new(200)
{
EmptySlot(EquipSlot.Ears),
EmptyNpc(EquipSlot.Ears),
},
};
foreach (var item in sheet)
{
var name = item.Name.ToString();
if (!name.Any())
continue;
var slot = (EquipSlot)item.EquipSlotCategory.Row;
if (slot == EquipSlot.Unknown)
continue;
slot = slot.ToSlot();
if (slot == EquipSlot.OffHand)
slot = EquipSlot.MainHand;
if (_itemsBySlot.TryGetValue(slot, out var list))
list.Add(new Item2(item, name, slot));
}
foreach (var list in _itemsBySlot.Values)
list.Sort((i1, i2) => string.Compare(i1.Name, i2.Name, StringComparison.InvariantCulture));
_itemsBySlot[EquipSlot.LFinger] = _itemsBySlot[EquipSlot.RFinger];
return _itemsBySlot;
}
public static IReadOnlyDictionary<byte, Job> Jobs(DataManager dataManager)
{
if (_jobs != null)

View file

@ -144,7 +144,7 @@ public unsafe class PenumbraAttach : IDisposable
{
var current = actor.DrawObject.Equip[item2.EquippableTo];
var armor = new CharacterArmor(item2.MainModel.id, (byte)item2.MainModel.variant, current.Stain);
Glamourer.RedrawManager.ChangeEquip(actor.DrawObject, item2.EquippableTo, armor);
Glamourer.RedrawManager.UpdateSlot(actor.DrawObject, item2.EquippableTo, armor);
return;
}
}

View file

@ -1,4 +1,6 @@
using Penumbra.GameData.Enums;
using Dalamud.Utility;
using Glamourer.Util;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Designs;
@ -18,6 +20,8 @@ public readonly struct Item
public StainId Stain
=> Model.Stain;
public Item WithStain(StainId id)
=> new(Name, ItemId, Model with { Stain = id });
public Item(string name, uint itemId, CharacterArmor armor)
{
@ -27,6 +31,14 @@ public readonly struct Item
Model.Variant = armor.Variant;
Model.Stain = armor.Stain;
}
public Item(Lumina.Excel.GeneratedSheets.Item item)
{
Name = string.Intern(item.Name.ToDalamudString().TextValue);
ItemId = item.RowId;
Model.Set = (SetId)item.ModelMain;
Model.Variant = (byte)(item.ModelMain >> 16);
}
}
public readonly struct Weapon

View file

@ -93,7 +93,7 @@ public class Glamourer : IDalamudPlugin
HelpMessage = $"Use Glamourer Functions: {HelpString}",
});
_interface = new Interface(CurrentManipulations, _designManager, _fileSystem);
_interface = new Interface(Items, CurrentManipulations, _designManager, _fileSystem);
_windowSystem.AddWindow(_interface);
Dalamud.PluginInterface.UiBuilder.Draw += _windowSystem.Draw;
//FixedDesignManager.Flag((Human*)((Actor)Dalamud.ClientState.LocalPlayer?.Address).Pointer->GameObject.DrawObject, 0, &x);

View file

@ -1,360 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Interface;
using Glamourer.Structs;
using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using Lumina.Text;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Widgets;
using Penumbra.GameData;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui.Equipment;
public partial class EquipmentDrawer
{
public const int ItemComboWidth = 320;
private sealed class ItemCombo : FilterComboBase<Item2>
{
public readonly string Label;
public readonly EquipSlot Slot;
public Item? LastItem;
private CharacterArmor _lastArmor;
private string _lastPreview = string.Empty;
private int _lastIndex;
public ItemCombo(EquipSlot slot)
: base(GetItems(slot), false)
{
Label = GetLabel(slot);
Slot = slot;
}
protected override string ToString(Item2 obj)
=> obj.Name;
private static string GetLabel(EquipSlot slot)
{
var sheet = Dalamud.GameData.GetExcelSheet<Addon>()!;
return slot switch
{
EquipSlot.Head => sheet.GetRow(740)?.Text.ToString() ?? "Head",
EquipSlot.Body => sheet.GetRow(741)?.Text.ToString() ?? "Body",
EquipSlot.Hands => sheet.GetRow(742)?.Text.ToString() ?? "Hands",
EquipSlot.Legs => sheet.GetRow(744)?.Text.ToString() ?? "Legs",
EquipSlot.Feet => sheet.GetRow(745)?.Text.ToString() ?? "Feet",
EquipSlot.Ears => sheet.GetRow(746)?.Text.ToString() ?? "Ears",
EquipSlot.Neck => sheet.GetRow(747)?.Text.ToString() ?? "Neck",
EquipSlot.Wrists => sheet.GetRow(748)?.Text.ToString() ?? "Wrists",
EquipSlot.RFinger => sheet.GetRow(749)?.Text.ToString() ?? "Right Ring",
EquipSlot.LFinger => sheet.GetRow(750)?.Text.ToString() ?? "Left Ring",
_ => string.Empty,
};
}
public bool Draw(CharacterArmor armor, out int newIdx)
{
UpdateItem(armor);
newIdx = _lastIndex;
return Draw(Label, _lastPreview, ref newIdx, ItemComboWidth * ImGuiHelpers.GlobalScale, ImGui.GetTextLineHeight());
}
private void UpdateItem(CharacterArmor armor)
{
if (armor.Equals(_lastArmor))
return;
_lastArmor = armor;
LastItem = Identify(armor.Set, 0, armor.Variant, Slot);
_lastIndex = Items.IndexOf(i => i.Base.RowId == LastItem.RowId);
_lastPreview = _lastIndex >= 0 ? Items[_lastIndex].Name : LastItem.Name.ToString();
}
private static IReadOnlyList<Item2> GetItems(EquipSlot slot)
=> GameData.ItemsBySlot(Dalamud.GameData).TryGetValue(slot, out var list) ? list : Array.Empty<Item2>();
}
private sealed class WeaponCombo : FilterComboBase<Item2>
{
public readonly string Label;
public readonly EquipSlot Slot;
public Item? LastItem;
private CharacterWeapon _lastWeapon = new(ulong.MaxValue);
private string _lastPreview = string.Empty;
private int _lastIndex;
public FullEquipType LastCategory { get; private set; }
private bool _drawAll;
public WeaponCombo(EquipSlot slot)
: base(GetItems(slot), false)
{
Label = GetLabel(slot);
Slot = slot;
}
protected override string ToString(Item2 obj)
=> obj.Name;
private static string GetLabel(EquipSlot slot)
{
var sheet = Dalamud.GameData.GetExcelSheet<Addon>()!;
return slot switch
{
EquipSlot.MainHand => sheet.GetRow(738)?.Text.ToString() ?? "Main Hand",
EquipSlot.OffHand => sheet.GetRow(739)?.Text.ToString() ?? "Off Hand",
_ => string.Empty,
};
}
public bool Draw(CharacterWeapon weapon, out int newIdx, bool drawAll)
{
if (drawAll != _drawAll)
{
_drawAll = drawAll;
ResetFilter();
}
UpdateItem(weapon);
UpdateCategory(((WeaponCategory)(LastItem!.ItemUICategory?.Row ?? 0)).ToEquipType());
newIdx = _lastIndex;
return Draw(Label, _lastPreview, ref newIdx, ItemComboWidth * ImGuiHelpers.GlobalScale, ImGui.GetTextLineHeight());
}
public bool Draw(CharacterWeapon weapon, FullEquipType category, out int newIdx)
{
if (_drawAll)
{
_drawAll = false;
ResetFilter();
}
UpdateItem(weapon);
UpdateCategory(category);
newIdx = _lastIndex;
return Draw(Label, _lastPreview, ref newIdx, ItemComboWidth * ImGuiHelpers.GlobalScale, ImGui.GetTextLineHeight());
}
//protected override bool DrawSelectable(int globalIdx, bool selected)
//{
// using var _ = ImRaii.Group();
//
//}
protected override bool IsVisible(int globalIndex, LowerString filter)
{
var item = Items[globalIndex];
return (_drawAll || item.WeaponCategory == LastCategory) && filter.IsContained(item.Name);
}
private void UpdateItem(CharacterWeapon weapon)
{
if (weapon.Equals(_lastWeapon))
return;
_lastWeapon = weapon;
LastItem = Identify(weapon.Set, weapon.Type, weapon.Variant, Slot);
_lastIndex = LastItem.RowId == 0 ? -1 : Items.IndexOf(i => i.Base.RowId == LastItem.RowId);
_lastPreview = _lastIndex >= 0 ? Items[_lastIndex].Name : LastItem.Name.ToString();
}
private void UpdateCategory(FullEquipType category)
{
if (category == LastCategory)
return;
LastCategory = category;
ResetFilter();
}
private static IReadOnlyList<Item2> GetItems(EquipSlot slot)
=> GameData.ItemsBySlot(Dalamud.GameData).TryGetValue(EquipSlot.MainHand, out var list) ? list : Array.Empty<Item2>();
}
private static readonly IObjectIdentifier Identifier;
private static readonly IReadOnlyList<ItemCombo> ItemCombos;
private static readonly WeaponCombo MainHandCombo;
private static readonly WeaponCombo OffHandCombo;
private void DrawItemSelector()
{
var combo = ItemCombos[(int)_currentSlotIdx];
var change = combo.Draw(_currentArmor, out var idx);
var newItem = change ? ToArmor(combo.Items[idx], _currentArmor.Stain) : CharacterArmor.Empty;
if (!change && !ReferenceEquals(combo.LastItem, SmallClothes))
{
ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
change = true;
}
if (!change)
return;
_currentArmor = newItem;
UpdateActors();
}
private static CharacterArmor ToArmor(Item2 item2, StainId stain)
{
var (id, _, variant) = item2.MainModel;
return new CharacterArmor(id, (byte)variant, stain);
}
private static CharacterWeapon ToWeapon(Item2 item2, StainId stain)
{
var (id, type, variant) = item2.MainModel;
return new CharacterWeapon(id, type, variant, stain);
}
private void DrawMainHandSelector(ref CharacterWeapon mainHand)
{
if (!MainHandCombo.Draw(mainHand, out var newIdx, false))
return;
mainHand = ToWeapon(MainHandCombo.Items[newIdx], mainHand.Stain);
foreach (var actor in _actors)
Glamourer.RedrawManager.LoadWeapon(actor, _currentSlot, mainHand);
}
private void DrawOffHandSelector(ref CharacterWeapon offHand, FullEquipType category)
{
var change = OffHandCombo.Draw(offHand, category, out var newIdx);
var newWeapon = change ? ToWeapon(OffHandCombo.Items[newIdx], offHand.Stain) : CharacterWeapon.Empty;
if (!change && !ReferenceEquals(OffHandCombo.LastItem, SmallClothes))
{
ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
change = true;
}
if (!change)
return;
offHand = newWeapon;
foreach (var actor in _actors)
Glamourer.RedrawManager.LoadWeapon(actor, _currentSlot, offHand);
}
//private bool DrawEquipSlot(EquipSlot slot, CharacterArmor equip)
//{
// var (equipCombo, stainCombo) = _combos[slot];
//
// var ret = DrawStainSelector(stainCombo, slot, equip.Stain);
// ImGui.SameLine();
// var item = Identify(equip.Set, new WeaponType(), equip.Variant, slot);
// ret |= DrawItemSelector(equipCombo, item, slot);
//
// return ret;
//}
//
//private bool DrawEquipSlotWithCheck(EquipSlot slot, CharacterArmor equip, CharacterEquipMask flag, ref CharacterEquipMask mask)
//{
// var ret = DrawCheckbox(flag, ref mask);
// ImGui.SameLine();
// ret |= DrawEquipSlot(slot, equip);
// return ret;
//}
//
//private bool DrawWeapon(EquipSlot slot, CharacterWeapon weapon)
//{
// var (equipCombo, stainCombo) = _combos[slot];
//
// var ret = DrawStainSelector(stainCombo, slot, weapon.Stain);
// ImGui.SameLine();
// var item = Identify(weapon.Set, weapon.Type, weapon.Variant, slot);
// ret |= DrawItemSelector(equipCombo, item, slot);
//
// return ret;
//}
//
//private bool DrawWeaponWithCheck(EquipSlot slot, CharacterWeapon weapon, CharacterEquipMask flag, ref CharacterEquipMask mask)
//{
// var ret = DrawCheckbox(flag, ref mask);
// ImGui.SameLine();
// ret |= DrawWeapon(slot, weapon);
// return ret;
//}
//
//private bool DrawEquip(CharacterEquipment equip)
//{
// var ret = false;
// if (ImGui.CollapsingHeader("Character Equipment"))
// {
// ret |= DrawWeapon(EquipSlot.MainHand, equip.MainHand);
// ret |= DrawWeapon(EquipSlot.OffHand, equip.OffHand);
// ret |= DrawEquipSlot(EquipSlot.Head, equip.Head);
// ret |= DrawEquipSlot(EquipSlot.Body, equip.Body);
// ret |= DrawEquipSlot(EquipSlot.Hands, equip.Hands);
// ret |= DrawEquipSlot(EquipSlot.Legs, equip.Legs);
// ret |= DrawEquipSlot(EquipSlot.Feet, equip.Feet);
// ret |= DrawEquipSlot(EquipSlot.Ears, equip.Ears);
// ret |= DrawEquipSlot(EquipSlot.Neck, equip.Neck);
// ret |= DrawEquipSlot(EquipSlot.Wrists, equip.Wrists);
// ret |= DrawEquipSlot(EquipSlot.RFinger, equip.RFinger);
// ret |= DrawEquipSlot(EquipSlot.LFinger, equip.LFinger);
// }
//
// return ret;
//}
//
//private bool DrawEquip(CharacterEquipment equip, ref CharacterEquipMask mask)
//{
// var ret = false;
// if (ImGui.CollapsingHeader("Character Equipment"))
// {
// ret |= DrawWeaponWithCheck(EquipSlot.MainHand, equip.MainHand, CharacterEquipMask.MainHand, ref mask);
// ret |= DrawWeaponWithCheck(EquipSlot.OffHand, equip.OffHand, CharacterEquipMask.OffHand, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.Head, equip.Head, CharacterEquipMask.Head, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.Body, equip.Body, CharacterEquipMask.Body, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.Hands, equip.Hands, CharacterEquipMask.Hands, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.Legs, equip.Legs, CharacterEquipMask.Legs, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.Feet, equip.Feet, CharacterEquipMask.Feet, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.Ears, equip.Ears, CharacterEquipMask.Ears, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.Neck, equip.Neck, CharacterEquipMask.Neck, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.Wrists, equip.Wrists, CharacterEquipMask.Wrists, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.RFinger, equip.RFinger, CharacterEquipMask.RFinger, ref mask);
// ret |= DrawEquipSlotWithCheck(EquipSlot.LFinger, equip.LFinger, CharacterEquipMask.LFinger, ref mask);
// }
//
// return ret;
//}
//
//
//
private static readonly Item SmallClothes = new()
{
Name = new SeString("Nothing"),
RowId = 0,
};
private static readonly Item SmallClothesNpc = new()
{
Name = new SeString("Smallclothes (NPC)"),
RowId = 1,
};
private static readonly Item Unknown = new()
{
Name = new SeString("Unknown"),
RowId = 2,
};
private static Item Identify(SetId set, WeaponType weapon, ushort variant, EquipSlot slot)
{
return (uint)set switch
{
0 => SmallClothes,
9903 => SmallClothesNpc,
_ => Identifier.Identify(set, weapon, variant, slot.ToSlot()).FirstOrDefault(Unknown),
};
}
}

View file

@ -1,157 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Glamourer.Customization;
using Glamourer.Interop;
using ImGuiNET;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui.Equipment;
public enum ApplicationFlags
{ }
public partial class EquipmentDrawer
{
private static readonly FilterComboColors StainCombo;
private static readonly StainData StainData;
private Race _race;
private Gender _gender;
private CharacterEquip _equip;
private IReadOnlyCollection<Actor> _actors = Array.Empty<Actor>();
private CharacterArmor _currentArmor;
private EquipSlot _currentSlot;
private uint _currentSlotIdx;
static EquipmentDrawer()
{
StainData = Glamourer.Items.Stains;
StainCombo = new FilterComboColors(140,
StainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))));
Identifier = Glamourer.Items.Identifier;
ItemCombos = EquipSlotExtensions.EqdpSlots.Select(s => new ItemCombo(s)).ToArray();
MainHandCombo = new WeaponCombo(EquipSlot.MainHand);
OffHandCombo = new WeaponCombo(EquipSlot.OffHand);
}
public static void Draw(Customize customize, CharacterEquip equip, ref CharacterWeapon mainHand, ref CharacterWeapon offHand,
IReadOnlyCollection<Actor> actors, bool locked)
{
var d = new EquipmentDrawer()
{
_race = customize.Race,
_gender = customize.Gender,
_equip = equip,
_actors = actors,
};
if (!ImGui.CollapsingHeader("Character Equipment"))
return;
using var disabled = ImRaii.Disabled(locked);
d.DrawInternal(ref mainHand, ref offHand);
}
public static void Draw(Customize customize, CharacterEquip equip, ref CharacterWeapon mainHand, ref CharacterWeapon offHand,
ref ApplicationFlags flags, IReadOnlyCollection<Actor> actors,
bool locked)
{
var d = new EquipmentDrawer()
{
_race = customize.Race,
_gender = customize.Gender,
_equip = equip,
_actors = actors,
};
if (!ImGui.CollapsingHeader("Character Equipment"))
return;
using var disabled = ImRaii.Disabled(locked);
d.DrawInternal(ref mainHand, ref offHand, ref flags);
}
private void DrawStainCombo()
{
var found = StainData.TryGetValue(_currentArmor.Stain, out var stain);
StainCombo.Draw("##stain", stain.RgbaColor, found);
}
private void DrawInternal(ref CharacterWeapon mainHand, ref CharacterWeapon offHand)
{
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
using var id = SetSlot(slot);
DrawStainCombo();
ImGui.SameLine();
DrawItemSelector();
}
_currentSlot = EquipSlot.MainHand;
DrawStainCombo();
ImGui.SameLine();
DrawMainHandSelector(ref mainHand);
var offhand = MainHandCombo.LastCategory.Offhand();
if (offhand != FullEquipType.Unknown)
{
_currentSlot = EquipSlot.OffHand;
DrawStainCombo();
ImGui.SameLine();
DrawOffHandSelector(ref offHand, offhand);
}
}
private void DrawInternal(ref CharacterWeapon mainHand, ref CharacterWeapon offHand, ref ApplicationFlags flags)
{
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
using var id = SetSlot(slot);
DrawCheckbox(ref flags);
ImGui.SameLine();
DrawStainCombo();
ImGui.SameLine();
DrawItemSelector();
}
_currentSlot = EquipSlot.MainHand;
DrawCheckbox(ref flags);
ImGui.SameLine();
DrawStainCombo();
ImGui.SameLine();
DrawMainHandSelector(ref mainHand);
var offhand = MainHandCombo.LastCategory.Offhand();
if (offhand != FullEquipType.Unknown)
{
_currentSlot = EquipSlot.OffHand;
DrawCheckbox(ref flags);
ImGui.SameLine();
DrawStainCombo();
ImGui.SameLine();
DrawOffHandSelector(ref offHand, offhand);
}
}
private ImRaii.Id SetSlot(EquipSlot slot)
{
_currentSlot = slot;
_currentSlotIdx = slot.ToIndex();
_currentArmor = _equip[slot];
return ImRaii.PushId((int)slot);
}
private void UpdateActors()
{
_equip[_currentSlotIdx] = _currentArmor;
foreach (var actor in _actors)
Glamourer.RedrawManager.ChangeEquip(actor, _currentSlotIdx, _currentArmor);
}
}

View file

@ -1,19 +0,0 @@
using ImGuiNET;
using OtterGui;
namespace Glamourer.Gui.Equipment;
public partial class EquipmentDrawer
{
private void DrawCheckbox(ref ApplicationFlags flags)
=> DrawCheckbox("##checkbox", "Enable writing this slot in this save.", ref flags, 0);
private static void DrawCheckbox(string label, string tooltip, ref ApplicationFlags flags, ApplicationFlags flag)
{
var tmp = (uint)flags;
if (ImGui.CheckboxFlags(label, ref tmp, (uint)flag))
flags = (ApplicationFlags)tmp;
ImGuiUtil.HoverTooltip(tooltip);
}
}

View file

@ -0,0 +1,63 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Dalamud.Interface;
using Glamourer.Designs;
using Glamourer.Util;
using ImGuiNET;
using OtterGui;
using OtterGui.Widgets;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui.Equipment;
public partial class EquipmentDrawer
{
private readonly FilterComboColors _stainCombo;
private readonly StainData _stainData;
private readonly ItemCombo[] _itemCombo;
public EquipmentDrawer(ItemManager items)
{
_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(items, e)).ToArray();
}
public bool DrawArmor(DesignBase design, EquipSlot slot, out Item armor)
{
Debug.Assert(slot.IsEquipment() || slot.IsAccessory());
var combo = _itemCombo[slot.ToIndex()];
armor = design.Armor(slot);
var change = combo.Draw(armor.Name, armor.ItemId, 320 * ImGuiHelpers.GlobalScale);
if (armor.ModelBase.Value != 0)
{
ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
change = true;
armor = ItemManager.NothingItem(slot);
}
}
else if (change)
{
armor = combo.CurrentSelection.WithStain(armor.Stain);
}
return change;
}
public bool DrawStain(DesignBase design, EquipSlot slot, out Stain stain)
{
Debug.Assert(slot.IsEquipment() || slot.IsAccessory());
var armor = design.Armor(slot);
var found = _stainData.TryGetValue(armor.Stain, out stain);
if (!_stainCombo.Draw($"##stain{slot}", stain.RgbaColor, found))
return false;
return _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain);
}
}

View file

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Dalamud.Interface;
using Glamourer.Structs;
using Glamourer.Util;
using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Item = Glamourer.Designs.Item;
namespace Glamourer.Gui.Equipment;
public sealed class ItemCombo : FilterComboCache<Item>
{
public readonly string Label;
public readonly EquipSlot Slot;
private uint _lastItemId;
private uint _previewId;
public ItemCombo(ItemManager items, EquipSlot slot)
: base(GetItems(items, slot))
{
Label = GetLabel(slot);
Slot = slot;
_lastItemId = ItemManager.NothingId(slot);
_previewId = _lastItemId;
}
protected override void DrawList(float width, float itemHeight)
{
if (_previewId != _lastItemId)
{
_lastItemId = _previewId;
CurrentSelectionIdx = Items.IndexOf(i => i.ItemId == _lastItemId);
CurrentSelection = Items[CurrentSelectionIdx];
}
base.DrawList(width, itemHeight);
if (NewSelection != null && Items.Count > NewSelection.Value)
CurrentSelection = Items[NewSelection.Value];
}
public bool Draw(string previewName, uint previewIdx, float width)
{
_previewId = previewIdx;
return Draw(Label, previewName, width, ImGui.GetTextLineHeightWithSpacing());
}
protected override bool DrawSelectable(int globalIdx, bool selected)
{
var obj = Items[globalIdx];
var name = ToString(obj);
var ret = ImGui.Selectable(name, selected);
using var color = ImRaii.PushColor(ImGuiCol.Text, 0xFF808080);
ImGuiUtil.RightAlign($"({obj.ModelBase.Value}-{obj.Variant})");
return ret;
}
protected override bool IsVisible(int globalIndex, LowerString filter)
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].ModelBase.ToString());
protected override string ToString(Item obj)
=> obj.Name;
private static string GetLabel(EquipSlot slot)
{
var sheet = Dalamud.GameData.GetExcelSheet<Addon>()!;
return slot switch
{
EquipSlot.Head => sheet.GetRow(740)?.Text.ToString() ?? "Head",
EquipSlot.Body => sheet.GetRow(741)?.Text.ToString() ?? "Body",
EquipSlot.Hands => sheet.GetRow(742)?.Text.ToString() ?? "Hands",
EquipSlot.Legs => sheet.GetRow(744)?.Text.ToString() ?? "Legs",
EquipSlot.Feet => sheet.GetRow(745)?.Text.ToString() ?? "Feet",
EquipSlot.Ears => sheet.GetRow(746)?.Text.ToString() ?? "Ears",
EquipSlot.Neck => sheet.GetRow(747)?.Text.ToString() ?? "Neck",
EquipSlot.Wrists => sheet.GetRow(748)?.Text.ToString() ?? "Wrists",
EquipSlot.RFinger => sheet.GetRow(749)?.Text.ToString() ?? "Right Ring",
EquipSlot.LFinger => sheet.GetRow(750)?.Text.ToString() ?? "Left Ring",
_ => string.Empty,
};
}
private static IEnumerable<Item> GetItems(ItemManager items, EquipSlot slot)
{
var nothing = ItemManager.NothingItem(slot);
if (!items.Items.TryGetValue(slot.ToEquipType(), out var list))
return new[] { nothing };
return list.Select(i => new Item(i)).Append(ItemManager.SmallClothesItem(slot)).OrderBy(i => i.Name).Prepend(nothing);
}
}

View file

@ -10,6 +10,7 @@ using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
using ImGui = ImGuiNET.ImGui;
namespace Glamourer.Gui;
@ -18,10 +19,14 @@ internal partial class Interface
{
private class ActorTab
{
private readonly Interface _main;
private readonly CurrentManipulations _manipulations;
public ActorTab(CurrentManipulations manipulations)
=> _manipulations = manipulations;
public ActorTab(Interface main, CurrentManipulations manipulations)
{
_main = main;
_manipulations = manipulations;
}
private ActorIdentifier _identifier = ActorIdentifier.Invalid;
private ObjectManager.ActorData _currentData = ObjectManager.ActorData.Invalid;
@ -61,11 +66,15 @@ internal partial class Interface
_currentSave.Update(_currentData.Objects[0]);
RevertButton();
CustomizationDrawer.Draw(_currentSave.Data.Customize, _currentSave.Data.Equipment, _currentData.Objects,
CustomizationDrawer.Draw(_currentSave.Customize(), _currentSave.Equipment(), _currentData.Objects,
_identifier.Type == IdentifierType.Special);
EquipmentDrawer.Draw(_currentSave.Data.Customize, _currentSave.Data.Equipment, ref _currentSave.Data.MainHand,
ref _currentSave.Data.OffHand, _currentData.Objects, _identifier.Type == IdentifierType.Special);
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
_main._equipmentDrawer.DrawStain(_currentSave, slot, out var stain);
ImGui.SameLine();
_main._equipmentDrawer.DrawArmor(_currentSave, slot, out var armor);
}
}
private const uint RedHeaderColor = 0xFF1818C0;
@ -77,13 +86,13 @@ internal partial class Interface
{
_manipulations.DeleteSave(_identifier);
foreach (var actor in _currentData.Objects)
_currentSave!.ApplyToActor(actor);
if (_currentData.Objects.Count > 0)
_currentSave = _manipulations.GetOrCreateSave(_currentData.Objects[0]);
_currentSave!.Reset();
//foreach (var actor in _currentData.Objects)
// _currentSave!.ApplyToActor(actor);
//
//if (_currentData.Objects.Count > 0)
// _currentSave = _manipulations.GetOrCreateSave(_currentData.Objects[0]);
//
//_currentSave!.Reset();
}
if (_currentData.Objects.Count > 0)

View file

@ -95,7 +95,6 @@ internal partial class Interface
using var group = ImRaii.Group();
if (ImGui.Button("Delete"))
_delete = true;
CustomizationDrawer.Draw(_save!.Data.Customize, _save.Data.Equipment, Array.Empty<Actor>(), false);
}
}
}

View file

@ -8,6 +8,7 @@ using Glamourer.Gui.Equipment;
using Glamourer.Interop;
using ImGuiNET;
using OtterGui.Raii;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui;
@ -17,11 +18,13 @@ internal partial class Interface
private class DesignTab : IDisposable
{
public readonly DesignFileSystemSelector Selector;
private readonly Interface _main;
private readonly DesignFileSystem _fileSystem;
private readonly Design.Manager _manager;
public DesignTab(Design.Manager manager, DesignFileSystem fileSystem)
public DesignTab(Interface main, Design.Manager manager, DesignFileSystem fileSystem)
{
_main = main;
_manager = manager;
_fileSystem = fileSystem;
Selector = new DesignFileSystemSelector(manager, fileSystem);
@ -53,12 +56,12 @@ internal partial class Interface
return;
CustomizationDrawer.Draw(Selector.Selected.Customize(), Selector.Selected.Equipment(), true);
var weapon = Selector.Selected.WeaponMain;
var mw = new CharacterWeapon(weapon.ModelBase, weapon.WeaponBase, weapon.Variant, weapon.Stain);
weapon = Selector.Selected.WeaponOff;
var ow = new CharacterWeapon(weapon.ModelBase, weapon.WeaponBase, weapon.Variant, weapon.Stain);
ApplicationFlags f = 0;
EquipmentDrawer.Draw(Selector.Selected.Customize(), Selector.Selected.Equipment(), ref mw, ref ow, ref f, Array.Empty<Actor>(), true);
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
_main._equipmentDrawer.DrawStain(Selector.Selected, slot, out var stain);
ImGui.SameLine();
_main._equipmentDrawer.DrawArmor(Selector.Selected, slot, out var armor);
}
}
}
}

View file

@ -5,22 +5,28 @@ using Dalamud.Interface.Windowing;
using Dalamud.Logging;
using Glamourer.Designs;
using Glamourer.Gui.Customization;
using Glamourer.Gui.Equipment;
using Glamourer.State;
using Glamourer.Util;
using ImGuiNET;
using OtterGui.Raii;
using Penumbra.GameData.Data;
namespace Glamourer.Gui;
internal partial class Interface : Window, IDisposable
{
private readonly EquipmentDrawer _equipmentDrawer;
private readonly ActorTab _actorTab;
private readonly DesignTab _designTab;
private readonly DebugStateTab _debugStateTab;
private readonly DebugDataTab _debugDataTab;
public Interface(CurrentManipulations manipulations, Design.Manager manager, DesignFileSystem fileSystem)
public Interface(ItemManager items, CurrentManipulations manipulations, Design.Manager manager, DesignFileSystem fileSystem)
: base(GetLabel())
{
_equipmentDrawer = new EquipmentDrawer(items);
Dalamud.PluginInterface.UiBuilder.DisableGposeUiHide = true;
Dalamud.PluginInterface.UiBuilder.OpenConfigUi += Toggle;
SizeConstraints = new WindowSizeConstraints()
@ -28,10 +34,10 @@ internal partial class Interface : Window, IDisposable
MinimumSize = new Vector2(675, 675),
MaximumSize = ImGui.GetIO().DisplaySize,
};
_actorTab = new ActorTab(manipulations);
_actorTab = new ActorTab(this, manipulations);
_debugStateTab = new DebugStateTab(manipulations);
_debugDataTab = new DebugDataTab(Glamourer.Customization);
_designTab = new DesignTab(manager, fileSystem);
_designTab = new DesignTab(this, manager, fileSystem);
}
public override void Draw()

View file

@ -29,18 +29,18 @@ public unsafe partial class RedrawManager
private ulong FlagSlotForUpdateDetourBase(nint drawObject, uint slotIdx, CharacterArmor* data, bool manual)
{
try
{
var slot = slotIdx.ToEquipSlot();
Glamourer.Log.Verbose(
$"Flagged slot {slot} of 0x{(ulong)drawObject:X} for update with {data->Set.Value}-{data->Variant} (Stain {data->Stain.Value}).");
HandleEquipUpdate(drawObject, slot, ref *data, manual);
}
catch (Exception ex)
{
Glamourer.Log.Error($"Error invoking SlotUpdate:\n{ex}");
}
// try
// {
// var slot = slotIdx.ToEquipSlot();
// Glamourer.Log.Verbose(
// $"Flagged slot {slot} of 0x{(ulong)drawObject:X} for update with {data->Set.Value}-{data->Variant} (Stain {data->Stain.Value}).");
// HandleEquipUpdate(drawObject, slot, ref *data, manual);
// }
// catch (Exception ex)
// {
// Glamourer.Log.Error($"Error invoking SlotUpdate:\n{ex}");
// }
//
return _flagSlotForUpdateHook.Original(drawObject, slotIdx, data);
//try

View file

@ -48,15 +48,15 @@ public unsafe partial class RedrawManager
else if (redrawOnEquality == 1 && _currentManipulations.TryGetDesign(identifier, out var save2))
{
PluginLog.Information($"Loaded weapon from current design for {identifier}.");
switch (slot)
{
case 0:
save2.Data.MainHand = new CharacterWeapon(weapon);
break;
case 1:
save2.Data.OffHand = new CharacterWeapon(weapon);
break;
}
//switch (slot)
//{
// case 0:
// save2.MainHand = new CharacterWeapon(weapon);
// break;
// case 1:
// save2.Data.OffHand = new CharacterWeapon(weapon);
// break;
//}
}
}
catch (Exception e)

View file

@ -24,6 +24,11 @@ public sealed partial class ActiveDesign : DesignBase
private ActiveDesign()
{ }
public ActiveDesign(Actor actor)
{
Update(actor);
}
//public void ApplyToActor(Actor actor)
//{
// if (!actor)

View file

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Linq;
using Dalamud.Data;
using Dalamud.Plugin;
@ -53,6 +54,18 @@ public class ItemManager : IDisposable
public static uint NothingId(FullEquipType type)
=> uint.MaxValue - 384 - (uint)type;
public static Designs.Item NothingItem(EquipSlot slot)
{
Debug.Assert(slot.IsEquipment() || slot.IsAccessory());
return new Designs.Item(Nothing, NothingId(slot), CharacterArmor.Empty);
}
public static Designs.Item SmallClothesItem(EquipSlot slot)
{
Debug.Assert(slot.IsEquipment());
return new Designs.Item(SmallClothesNpc, SmallclothesId(slot), new CharacterArmor(SmallClothesNpcModel, 1, 0));
}
public (bool Valid, SetId Id, byte Variant, string ItemName) Resolve(EquipSlot slot, uint itemId, Item? item = null)
{
slot = slot.ToSlot();