mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
dupidu
This commit is contained in:
parent
e3a58340b3
commit
6a4b5fc3b2
15 changed files with 740 additions and 300 deletions
|
|
@ -77,6 +77,7 @@ public static class GameData
|
|||
EmptySlot(EquipSlot.Feet),
|
||||
EmptyNpc(EquipSlot.Feet),
|
||||
},
|
||||
[EquipSlot.MainHand] = new(2000),
|
||||
[EquipSlot.RFinger] = new(200)
|
||||
{
|
||||
EmptySlot(EquipSlot.RFinger),
|
||||
|
|
@ -87,8 +88,6 @@ public static class GameData
|
|||
EmptySlot(EquipSlot.Neck),
|
||||
EmptyNpc(EquipSlot.Neck),
|
||||
},
|
||||
[EquipSlot.MainHand] = new(1000) { EmptySlot(EquipSlot.MainHand) },
|
||||
[EquipSlot.OffHand] = new(200) { EmptySlot(EquipSlot.OffHand) },
|
||||
[EquipSlot.Wrists] = new(200)
|
||||
{
|
||||
EmptySlot(EquipSlot.Wrists),
|
||||
|
|
@ -112,10 +111,10 @@ public static class GameData
|
|||
continue;
|
||||
|
||||
slot = slot.ToSlot();
|
||||
if (!_itemsBySlot.TryGetValue(slot, out var list))
|
||||
continue;
|
||||
|
||||
list.Add(new Item(item, name, slot));
|
||||
if (slot == EquipSlot.OffHand)
|
||||
slot = EquipSlot.MainHand;
|
||||
if (_itemsBySlot.TryGetValue(slot, out var list))
|
||||
list.Add(new Item(item, name, slot));
|
||||
}
|
||||
|
||||
foreach (var list in _itemsBySlot.Values)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ public readonly struct Item
|
|||
public bool IsBothHand
|
||||
=> (EquipSlot)Base.EquipSlotCategory.Row == EquipSlot.BothHand;
|
||||
|
||||
public WeaponCategory WeaponCategory
|
||||
=> (WeaponCategory?) Base.ItemUICategory?.Row ?? WeaponCategory.Unknown;
|
||||
|
||||
// Create a new item from its sheet list with the given name and either the inferred equip slot or the given one.
|
||||
public Item(Lumina.Excel.GeneratedSheets.Item item, string name, EquipSlot slot = EquipSlot.Unknown)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ internal partial class CustomizationDrawer
|
|||
// Update all relevant Actors by calling the UpdateCustomize game function.
|
||||
private void UpdateActors()
|
||||
{
|
||||
foreach (var actor in _actors.Where(a => a && a.DrawObject))
|
||||
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _customize);
|
||||
foreach (var actor in _actors)
|
||||
Glamourer.RedrawManager.UpdateCustomize(actor, _customize);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ internal partial class CustomizationDrawer
|
|||
private void ListCombo()
|
||||
{
|
||||
ImGui.SetNextItemWidth(_comboSelectorSize * ImGui.GetIO().FontGlobalScale);
|
||||
using var combo = ImRaii.Combo("##combo", $"{_currentOption} #{_currentByte.Value + 1}");
|
||||
using var combo = ImRaii.Combo("##combo", $"{_currentOption} #{_currentByte.Value + 1}");
|
||||
|
||||
if (!combo)
|
||||
return;
|
||||
|
|
@ -83,8 +83,7 @@ internal partial class CustomizationDrawer
|
|||
if (ImGui.Checkbox(label, ref tmp) && tmp != current)
|
||||
{
|
||||
setter(tmp);
|
||||
foreach (var actor in _actors.Where(a => a && a.DrawObject))
|
||||
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _customize);
|
||||
UpdateActors();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,6 +98,7 @@ internal partial class CustomizationDrawer
|
|||
var data = _set.Data(_currentId, currentIndex, _customize.Face);
|
||||
UpdateValue(data.Value);
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip($"Input Range: [1, {_currentCount}]");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
353
Glamourer/Gui/Equipment/EquipmentDrawer.Items.cs
Normal file
353
Glamourer/Gui/Equipment/EquipmentDrawer.Items.cs
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Interface;
|
||||
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;
|
||||
using Item = Glamourer.Structs.Item;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public partial class EquipmentDrawer
|
||||
{
|
||||
public const int ItemComboWidth = 320;
|
||||
|
||||
private sealed class ItemCombo : FilterComboBase<Item>
|
||||
{
|
||||
public readonly string Label;
|
||||
public readonly EquipSlot Slot;
|
||||
|
||||
public Lumina.Excel.GeneratedSheets.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(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,
|
||||
};
|
||||
}
|
||||
|
||||
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<Item> GetItems(EquipSlot slot)
|
||||
=> GameData.ItemsBySlot(Dalamud.GameData).TryGetValue(slot, out var list) ? list : Array.Empty<Item>();
|
||||
}
|
||||
|
||||
private sealed class WeaponCombo : FilterComboBase<Item>
|
||||
{
|
||||
public readonly string Label;
|
||||
public readonly EquipSlot Slot;
|
||||
|
||||
public Lumina.Excel.GeneratedSheets.Item? LastItem;
|
||||
private CharacterWeapon _lastWeapon = new(ulong.MaxValue);
|
||||
private string _lastPreview = string.Empty;
|
||||
private int _lastIndex;
|
||||
public WeaponCategory LastCategory { get; private set; }
|
||||
private bool _drawAll;
|
||||
|
||||
public WeaponCombo(EquipSlot slot)
|
||||
: base(GetItems(slot), false)
|
||||
{
|
||||
Label = GetLabel(slot);
|
||||
Slot = slot;
|
||||
}
|
||||
|
||||
protected override string ToString(Item 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 ?? WeaponCategory.Unknown);
|
||||
newIdx = _lastIndex;
|
||||
return Draw(Label, _lastPreview, ref newIdx, ItemComboWidth * ImGuiHelpers.GlobalScale, ImGui.GetTextLineHeight());
|
||||
}
|
||||
|
||||
public bool Draw(CharacterWeapon weapon, WeaponCategory 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 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(WeaponCategory category)
|
||||
{
|
||||
if (category == LastCategory)
|
||||
return;
|
||||
|
||||
LastCategory = category;
|
||||
ResetFilter();
|
||||
}
|
||||
|
||||
private static IReadOnlyList<Item> GetItems(EquipSlot slot)
|
||||
=> GameData.ItemsBySlot(Dalamud.GameData).TryGetValue(EquipSlot.MainHand, out var list) ? list : Array.Empty<Item>();
|
||||
}
|
||||
|
||||
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(Item item, StainId stain)
|
||||
{
|
||||
var (id, _, variant) = item.MainModel;
|
||||
return new CharacterArmor(id, (byte)variant, stain);
|
||||
}
|
||||
|
||||
private static CharacterWeapon ToWeapon(Item item, StainId stain)
|
||||
{
|
||||
var (id, type, variant) = item.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, WeaponCategory 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 Lumina.Excel.GeneratedSheets.Item SmallClothes = new()
|
||||
{
|
||||
Name = new SeString("Nothing"),
|
||||
RowId = 0,
|
||||
};
|
||||
|
||||
private static readonly Lumina.Excel.GeneratedSheets.Item SmallClothesNpc = new()
|
||||
{
|
||||
Name = new SeString("Smallclothes (NPC)"),
|
||||
RowId = 1,
|
||||
};
|
||||
|
||||
private static readonly Lumina.Excel.GeneratedSheets.Item Unknown = new()
|
||||
{
|
||||
Name = new SeString("Unknown"),
|
||||
RowId = 2,
|
||||
};
|
||||
|
||||
private static Lumina.Excel.GeneratedSheets.Item Identify(SetId set, WeaponType weapon, ushort variant, EquipSlot slot)
|
||||
{
|
||||
return (uint)set switch
|
||||
{
|
||||
0 => SmallClothes,
|
||||
9903 => SmallClothesNpc,
|
||||
_ => Identifier.Identify(set, weapon, variant, slot) ?? Unknown,
|
||||
};
|
||||
}
|
||||
}
|
||||
143
Glamourer/Gui/Equipment/EquipmentDrawer.Main.cs
Normal file
143
Glamourer/Gui/Equipment/EquipmentDrawer.Main.cs
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public partial class EquipmentDrawer
|
||||
{
|
||||
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()
|
||||
{
|
||||
Stains = GameData.Stains(Dalamud.GameData);
|
||||
StainCombo = new FilterStainCombo(140);
|
||||
Identifier = Penumbra.GameData.GameData.GetIdentifier(Dalamud.GameData);
|
||||
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 DrawInternal(ref CharacterWeapon mainHand, ref CharacterWeapon offHand)
|
||||
{
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
using var id = SetSlot(slot);
|
||||
DrawStainSelector();
|
||||
ImGui.SameLine();
|
||||
DrawItemSelector();
|
||||
}
|
||||
|
||||
_currentSlot = EquipSlot.MainHand;
|
||||
DrawStainSelector();
|
||||
ImGui.SameLine();
|
||||
DrawMainHandSelector(ref mainHand);
|
||||
var offhand = MainHandCombo.LastCategory.AllowsOffHand();
|
||||
if (offhand != WeaponCategory.Unknown)
|
||||
{
|
||||
_currentSlot = EquipSlot.OffHand;
|
||||
DrawStainSelector();
|
||||
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();
|
||||
DrawStainSelector();
|
||||
ImGui.SameLine();
|
||||
DrawItemSelector();
|
||||
}
|
||||
|
||||
_currentSlot = EquipSlot.MainHand;
|
||||
DrawCheckbox(ref flags);
|
||||
ImGui.SameLine();
|
||||
DrawStainSelector();
|
||||
ImGui.SameLine();
|
||||
DrawMainHandSelector(ref mainHand);
|
||||
var offhand = MainHandCombo.LastCategory.AllowsOffHand();
|
||||
if (offhand != WeaponCategory.Unknown)
|
||||
{
|
||||
_currentSlot = EquipSlot.OffHand;
|
||||
DrawCheckbox(ref flags);
|
||||
ImGui.SameLine();
|
||||
DrawStainSelector();
|
||||
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);
|
||||
}
|
||||
}
|
||||
95
Glamourer/Gui/Equipment/EquipmentDrawer.Misc.cs
Normal file
95
Glamourer/Gui/Equipment/EquipmentDrawer.Misc.cs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Stain = Glamourer.Structs.Stain;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public partial class EquipmentDrawer
|
||||
{
|
||||
private static readonly IReadOnlyDictionary<StainId, Stain> Stains;
|
||||
private static readonly FilterStainCombo StainCombo;
|
||||
|
||||
private sealed class FilterStainCombo : FilterComboBase<Stain>
|
||||
{
|
||||
private readonly float _comboWidth;
|
||||
private Vector2 _buttonSize;
|
||||
|
||||
public FilterStainCombo(float comboWidth)
|
||||
: base(Stains.Values.ToArray(), false)
|
||||
=> _comboWidth = comboWidth;
|
||||
|
||||
protected override float GetFilterWidth()
|
||||
=> _buttonSize.X + ImGui.GetStyle().ScrollbarSize;
|
||||
|
||||
protected override void DrawList(float width, float itemHeight)
|
||||
{
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||
.Push(ImGuiStyleVar.WindowPadding, Vector2.Zero)
|
||||
.Push(ImGuiStyleVar.FrameRounding, 0);
|
||||
_buttonSize = new Vector2(_comboWidth * ImGuiHelpers.GlobalScale, 0);
|
||||
if (ImGui.GetScrollMaxY() > 0)
|
||||
_buttonSize.X += ImGui.GetStyle().ScrollbarSize;
|
||||
base.DrawList(width, itemHeight);
|
||||
}
|
||||
|
||||
protected override string ToString(Stain obj)
|
||||
=> obj.Name;
|
||||
|
||||
protected override bool DrawSelectable(int globalIdx, bool selected)
|
||||
{
|
||||
var stain = Items[globalIdx];
|
||||
// Push the stain color to type and if it is too bright, turn the text color black.
|
||||
using var colors = ImRaii.PushColor(ImGuiCol.Button, stain.RgbaColor)
|
||||
.Push(ImGuiCol.Text, 0xFF101010, stain.Intensity > 127)
|
||||
.Push(ImGuiCol.Border, 0xFF2020D0, selected);
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2f * ImGuiHelpers.GlobalScale, selected);
|
||||
return ImGui.Button(stain.Name, _buttonSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawStainSelector()
|
||||
{
|
||||
var foundIdx = StainCombo.Items.IndexOf(s => s.RowIndex.Equals(_currentArmor.Stain));
|
||||
var stain = foundIdx >= 0 ? StainCombo.Items[foundIdx] : default;
|
||||
using var color = ImRaii.PushColor(ImGuiCol.FrameBg, stain.RgbaColor, foundIdx >= 0);
|
||||
var change = StainCombo.Draw("##stainSelector", string.Empty, ref foundIdx, ImGui.GetFrameHeight(), ImGui.GetFrameHeight(),
|
||||
ImGuiComboFlags.NoArrowButton);
|
||||
if (!change && (byte)_currentArmor.Stain != 0)
|
||||
{
|
||||
ImGuiUtil.HoverTooltip($"{stain.Name}\nRight-click to clear.");
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
change = true;
|
||||
foundIdx = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (change)
|
||||
{
|
||||
_currentArmor = new CharacterArmor(_currentArmor.Set, _currentArmor.Variant,
|
||||
foundIdx >= 0 ? StainCombo.Items[foundIdx].RowIndex : Stain.None.RowIndex);
|
||||
UpdateActors();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCheckbox(ref ApplicationFlags flags)
|
||||
=> DrawCheckbox("##checkbox", "Enable writing this slot in this save.", ref flags, _currentSlot.ToApplicationFlag());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using Lumina.Text;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui;
|
||||
|
||||
internal partial class Interface
|
||||
{
|
||||
//public class EquipmentDrawer
|
||||
//{
|
||||
// private static readonly IReadOnlyDictionary<StainId, Stain> Stains;
|
||||
//
|
||||
// private Race _race;
|
||||
// private Gender _gender;
|
||||
// private CharacterEquip _equip;
|
||||
// private IReadOnlyCollection<Actor> _actors = Array.Empty<Actor>();
|
||||
//
|
||||
// static EquipmentDrawer()
|
||||
// => Stains = GameData.Stains(Dalamud.GameData);
|
||||
//
|
||||
// public static void Draw(Customize customize, CharacterEquip equip, IReadOnlyCollection<Actor> actors, bool locked)
|
||||
// {
|
||||
// var d = new EquipmentDrawer()
|
||||
// {
|
||||
// _race = customize.Race,
|
||||
// _gender = customize.Gender,
|
||||
// _actors = actors,
|
||||
// };
|
||||
//
|
||||
// if (!ImGui.CollapsingHeader("Character Equipment"))
|
||||
// return;
|
||||
//
|
||||
// using var disabled = ImRaii.Disabled(locked);
|
||||
// }
|
||||
//
|
||||
// private bool DrawStainSelector(ComboWithFilter<Stain> stainCombo, EquipSlot slot, StainId stainIdx)
|
||||
// {
|
||||
// stainCombo.PostPreview = null;
|
||||
// var found = Stains.TryGetValue(stainIdx, out var stain);
|
||||
// using var color = ImRaii.PushColor(ImGuiCol.FrameBg, stain.RgbaColor, found);
|
||||
// var change = stainCombo.Draw(string.Empty, out var newStain) && !newStain.RowIndex.Equals(stainIdx);
|
||||
// if ()
|
||||
// if (!change && (byte)stainIdx != 0)
|
||||
// {
|
||||
// ImGuiUtil.HoverTooltip("Right-click to clear.");
|
||||
// if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
// {
|
||||
// change = true;
|
||||
// newStain = Stain.None;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!change)
|
||||
// return false;
|
||||
//
|
||||
// if (_player == null)
|
||||
// return _inDesignMode && (_selection?.Data.WriteStain(slot, newStain.RowIndex) ?? false);
|
||||
//
|
||||
// Glamourer.RevertableDesigns.Add(_player);
|
||||
// newStain.Write(_player.Address, slot);
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// private bool DrawItemSelector(ComboWithFilter<Item> equipCombo, Lumina.Excel.GeneratedSheets.Item item, EquipSlot slot = EquipSlot.Unknown)
|
||||
// {
|
||||
// var currentName = item.Name.ToString();
|
||||
// var change = equipCombo.Draw(currentName, out var newItem, _itemComboWidth) && newItem.Base.RowId != item.RowId;
|
||||
// if (!change && !ReferenceEquals(item, SmallClothes))
|
||||
// {
|
||||
// ImGuiUtil.HoverTooltip("Right-click to clear.");
|
||||
// if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
// {
|
||||
// change = true;
|
||||
// newItem = Item.Nothing(slot);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!change)
|
||||
// return false;
|
||||
//
|
||||
// newItem = new Item(newItem.Base, newItem.Name, slot);
|
||||
// if (_player == null)
|
||||
// return _inDesignMode && (_selection?.Data.WriteItem(newItem) ?? false);
|
||||
//
|
||||
// Glamourer.RevertableDesigns.Add(_player);
|
||||
// newItem.Write(_player.Address);
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// private static bool DrawCheckbox(CharacterEquipMask flag, ref CharacterEquipMask mask)
|
||||
// {
|
||||
// var tmp = (uint)mask;
|
||||
// var ret = false;
|
||||
// if (ImGui.CheckboxFlags($"##flag_{(uint)flag}", ref tmp, (uint)flag) && tmp != (uint)mask)
|
||||
// {
|
||||
// mask = (CharacterEquipMask)tmp;
|
||||
// ret = true;
|
||||
// }
|
||||
//
|
||||
// if (ImGui.IsItemHovered())
|
||||
// ImGui.SetTooltip("Enable writing this slot in this save.");
|
||||
// return ret;
|
||||
// }
|
||||
//
|
||||
// private static readonly Lumina.Excel.GeneratedSheets.Item SmallClothes = new()
|
||||
// {
|
||||
// Name = new SeString("Nothing"),
|
||||
// RowId = 0,
|
||||
// };
|
||||
//
|
||||
// private static readonly Lumina.Excel.GeneratedSheets.Item SmallClothesNpc = new()
|
||||
// {
|
||||
// Name = new SeString("Smallclothes (NPC)"),
|
||||
// RowId = 1,
|
||||
// };
|
||||
//
|
||||
// private static readonly Lumina.Excel.GeneratedSheets.Item Unknown = new()
|
||||
// {
|
||||
// Name = new SeString("Unknown"),
|
||||
// RowId = 2,
|
||||
// };
|
||||
//
|
||||
// private Lumina.Excel.GeneratedSheets.Item Identify(SetId set, WeaponType weapon, ushort variant, EquipSlot slot)
|
||||
// {
|
||||
// return (uint)set switch
|
||||
// {
|
||||
// 0 => SmallClothes,
|
||||
// 9903 => SmallClothesNpc,
|
||||
// _ => _identifier.Identify(set, weapon, variant, slot) ?? Unknown,
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// 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;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using System.Numerics;
|
|||
using Dalamud.Interface;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Gui.Customization;
|
||||
using Glamourer.Gui.Equipment;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
|
|
@ -60,6 +61,8 @@ internal partial class Interface
|
|||
|
||||
CustomizationDrawer.Draw(_currentSave.Data.Customize, _currentSave.Data.Equipment, _currentData.Objects,
|
||||
_identifier is Actor.SpecialIdentifier);
|
||||
|
||||
EquipmentDrawer.Draw(_currentSave.Data.Customize, _currentSave.Data.Equipment, ref _currentSave.Data.MainHand, ref _currentSave.Data.OffHand, _currentData.Objects, _identifier is Actor.SpecialIdentifier);
|
||||
}
|
||||
|
||||
private const uint RedHeaderColor = 0xFF1818C0;
|
||||
|
|
|
|||
|
|
@ -10,19 +10,6 @@ namespace Glamourer.Gui;
|
|||
|
||||
//internal partial class Interface
|
||||
//{
|
||||
// // Push the stain color to type and if it is too bright, turn the text color black.
|
||||
// // Return number of pushed styles.
|
||||
// private static int PushColor(Stain stain, ImGuiCol type = ImGuiCol.Button)
|
||||
// {
|
||||
// ImGui.PushStyleColor(type, stain.RgbaColor);
|
||||
// if (stain.Intensity > 127)
|
||||
// {
|
||||
// ImGui.PushStyleColor(ImGuiCol.Text, 0xFF101010);
|
||||
// return 2;
|
||||
// }
|
||||
//
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -17,28 +17,28 @@ namespace Glamourer.Gui;
|
|||
//
|
||||
// private static readonly Vector4 GreyVector = new(0.5f, 0.5f, 0.5f, 1);
|
||||
//
|
||||
// private static ComboWithFilter<Stain> CreateDefaultStainCombo(IReadOnlyList<Stain> stains)
|
||||
// => new("##StainCombo", ColorComboWidth, ColorButtonWidth, stains,
|
||||
// s => s.Name.ToString())
|
||||
// {
|
||||
// Flags = ImGuiComboFlags.NoArrowButton | ImGuiComboFlags.HeightLarge,
|
||||
// PreList = () =>
|
||||
// {
|
||||
// ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
|
||||
// ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
||||
// ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 0);
|
||||
// },
|
||||
// PostList = () => { ImGui.PopStyleVar(3); },
|
||||
// CreateSelectable = s =>
|
||||
// {
|
||||
// var push = PushColor(s);
|
||||
// var ret = ImGui.Button($"{s.Name}##Stain{(byte)s.RowIndex}",
|
||||
// Vector2.UnitX * (ColorComboWidth - ImGui.GetStyle().ScrollbarSize));
|
||||
// ImGui.PopStyleColor(push);
|
||||
// return ret;
|
||||
// },
|
||||
// ItemsAtOnce = 12,
|
||||
// };
|
||||
// private static ComboWithFilter<Stain> CreateDefaultStainCombo(IReadOnlyList<Stain> stains)
|
||||
// => new("##StainCombo", ColorComboWidth, ColorButtonWidth, stains,
|
||||
// s => s.Name.ToString())
|
||||
// {
|
||||
// Flags = ImGuiComboFlags.NoArrowButton | ImGuiComboFlags.HeightLarge,
|
||||
// PreList = () =>
|
||||
// {
|
||||
// ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
|
||||
// ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
||||
// ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 0);
|
||||
// },
|
||||
// PostList = () => { ImGui.PopStyleVar(3); },
|
||||
// CreateSelectable = s =>
|
||||
// {
|
||||
// var push = PushColor(s);
|
||||
// var ret = ImGui.Button($"{s.Name}##Stain{(byte)s.RowIndex}",
|
||||
// Vector2.UnitX * (ColorComboWidth - ImGui.GetStyle().ScrollbarSize));
|
||||
// ImGui.PopStyleColor(push);
|
||||
// return ret;
|
||||
// },
|
||||
// ItemsAtOnce = 12,
|
||||
// };
|
||||
//
|
||||
// private ComboWithFilter<Item> CreateItemCombo(EquipSlot slot, IReadOnlyList<Item> items)
|
||||
// => new($"{_equipSlotNames[slot]}##Equip", ItemComboWidth, ItemComboWidth, items, i => i.Name)
|
||||
|
|
|
|||
|
|
@ -48,11 +48,33 @@ public unsafe partial struct DrawObject : IEquatable<DrawObject>, IDesignable
|
|||
public CharacterEquip Equip
|
||||
=> new((CharacterArmor*)Pointer->EquipSlotData);
|
||||
|
||||
public unsafe CharacterWeapon MainHand
|
||||
=> CharacterWeapon.Empty;
|
||||
public CharacterWeapon MainHand
|
||||
{
|
||||
get
|
||||
{
|
||||
var child = (byte*)Pointer->CharacterBase.DrawObject.Object.ChildObject;
|
||||
if (child == null)
|
||||
return CharacterWeapon.Empty;
|
||||
|
||||
return *(CharacterWeapon*)(child + 0x8F0);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe CharacterWeapon OffHand
|
||||
=> CharacterWeapon.Empty;
|
||||
{
|
||||
get
|
||||
{
|
||||
var child = Pointer->CharacterBase.DrawObject.Object.ChildObject;
|
||||
if (child == null)
|
||||
return CharacterWeapon.Empty;
|
||||
|
||||
var sibling = (byte*) child->NextSiblingObject;
|
||||
if (sibling == null)
|
||||
return CharacterWeapon.Empty;
|
||||
|
||||
return *(CharacterWeapon*)(child + 0x8F0);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe bool VisorEnabled
|
||||
=> (*(byte*)(Address + 0x90) & 0x40) != 0;
|
||||
|
|
@ -113,6 +135,7 @@ public unsafe partial struct Actor : IEquatable<Actor>, IDesignable
|
|||
ident = GetIdentifier();
|
||||
return true;
|
||||
}
|
||||
|
||||
ident = IIdentifier.Invalid;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -156,16 +179,16 @@ public unsafe partial struct Actor : IEquatable<Actor>, IDesignable
|
|||
public CharacterEquip Equip
|
||||
=> new((CharacterArmor*)Pointer->EquipSlotData);
|
||||
|
||||
public unsafe CharacterWeapon MainHand
|
||||
public CharacterWeapon MainHand
|
||||
{
|
||||
get => *(CharacterWeapon*)(Address + 0x06C0 + 0x10);
|
||||
set => *(CharacterWeapon*)(Address + 0x06C0 + 0x10) = value;
|
||||
get => *(CharacterWeapon*)&Pointer->DrawData.MainHandModel;
|
||||
set => *(CharacterWeapon*)&Pointer->DrawData.MainHandModel = value;
|
||||
}
|
||||
|
||||
public unsafe CharacterWeapon OffHand
|
||||
public CharacterWeapon OffHand
|
||||
{
|
||||
get => *(CharacterWeapon*)(Address + 0x06C0 + 0x10 + 0x68);
|
||||
set => *(CharacterWeapon*)(Address + 0x06C0 + 0x10 + 0x68) = value;
|
||||
get => *(CharacterWeapon*)&Pointer->DrawData.OffHandModel;
|
||||
set => *(CharacterWeapon*)&Pointer->DrawData.OffHandModel = value;
|
||||
}
|
||||
|
||||
public unsafe bool VisorEnabled
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
using System;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
||||
using Race = Penumbra.GameData.Enums.Race;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
|
@ -66,27 +70,30 @@ public unsafe partial class RedrawManager
|
|||
return _flagSlotForUpdateHook.Original(drawObject, slotIdx, data);
|
||||
}
|
||||
|
||||
|
||||
public bool ChangeEquip(DrawObject drawObject, EquipSlot slot, CharacterArmor data)
|
||||
public bool ChangeEquip(DrawObject drawObject, uint slotIdx, CharacterArmor data)
|
||||
{
|
||||
if (!drawObject)
|
||||
return false;
|
||||
|
||||
var slotIndex = slot.ToIndex();
|
||||
if (slotIndex > 9)
|
||||
if (slotIdx > 9)
|
||||
return false;
|
||||
|
||||
return FlagSlotForUpdateDetour(drawObject.Pointer, slotIndex, &data) != 0;
|
||||
return FlagSlotForUpdateDetour(drawObject.Pointer, slotIdx, &data) != 0;
|
||||
}
|
||||
|
||||
public bool ChangeEquip(Actor actor, EquipSlot slot, CharacterArmor data)
|
||||
=> actor && ChangeEquip(actor.DrawObject, slot, data);
|
||||
=> actor && ChangeEquip(actor.DrawObject, slot.ToIndex(), data);
|
||||
|
||||
public bool ChangeEquip(DrawObject drawObject, EquipSlot slot, CharacterArmor data)
|
||||
=> ChangeEquip(drawObject, slot.ToIndex(), data);
|
||||
|
||||
public bool ChangeEquip(Actor actor, uint slotIdx, CharacterArmor data)
|
||||
=> actor && ChangeEquip(actor.DrawObject, slotIdx, data);
|
||||
}
|
||||
|
||||
public unsafe partial class RedrawManager
|
||||
{
|
||||
// The character weapon object manipulated is inside the actual character.
|
||||
public const int CharacterWeaponOffset = 0x6C0;
|
||||
public static readonly int CharacterWeaponOffset = (int) Marshal.OffsetOf<Character>("DrawData");
|
||||
|
||||
public delegate void LoadWeaponDelegate(IntPtr offsetCharacter, uint slot, ulong weapon, byte redrawOnEquality, byte unk2,
|
||||
byte skipGameObject,
|
||||
|
|
@ -219,7 +226,7 @@ public unsafe partial class RedrawManager : IDisposable
|
|||
var gameObjectCustomize = new Customize((CustomizeData*)actor.Pointer->CustomizeData);
|
||||
if (gameObjectCustomize.Equals(customize))
|
||||
customize.Load(save.Data.Customize);
|
||||
|
||||
|
||||
// Compare game object equip data against draw object equip data for transformations.
|
||||
// Apply each piece of equip that should be applied if they correspond.
|
||||
var gameObjectEquip = new CharacterEquip((CharacterArmor*)actor.Pointer->EquipSlotData);
|
||||
|
|
@ -262,14 +269,24 @@ public unsafe partial class RedrawManager : IDisposable
|
|||
[Signature("E8 ?? ?? ?? ?? 41 0F B6 C5 66 41 89 86")]
|
||||
private readonly ChangeCustomizeDelegate _changeCustomize = null!;
|
||||
|
||||
public bool UpdateCustomize(DrawObject drawObject, Customize customize)
|
||||
public bool UpdateCustomize(Actor actor, Customize customize)
|
||||
{
|
||||
if (!drawObject.Valid)
|
||||
if (!actor.Valid || !actor.DrawObject.Valid)
|
||||
return false;
|
||||
|
||||
return _changeCustomize(drawObject.Pointer, (byte*)customize.Data, 1);
|
||||
|
||||
var d = actor.DrawObject;
|
||||
if (NeedsRedraw(d.Customize, customize))
|
||||
{
|
||||
Glamourer.Penumbra.RedrawObject(actor.Character, RedrawType.Redraw, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return _changeCustomize(d.Pointer, (byte*)customize.Data, 1);
|
||||
}
|
||||
|
||||
public static bool NeedsRedraw(Customize lhs, Customize rhs)
|
||||
=> lhs.Race != rhs.Race || lhs.Gender != rhs.Gender || lhs.Face != rhs.Face || lhs.Race == Race.Hyur && lhs.Clan != rhs.Clan;
|
||||
|
||||
|
||||
public static void SetVisor(Human* data, bool on)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,6 +57,53 @@ public enum ApplicationFlags : uint
|
|||
Wet = 0x040000,
|
||||
}
|
||||
|
||||
public static class ApplicationFlagExtensions
|
||||
{
|
||||
public static ApplicationFlags ToApplicationFlag(this EquipSlot slot)
|
||||
=> slot switch
|
||||
{
|
||||
EquipSlot.MainHand => ApplicationFlags.MainHand,
|
||||
EquipSlot.OffHand => ApplicationFlags.OffHand,
|
||||
EquipSlot.Head => ApplicationFlags.Head,
|
||||
EquipSlot.Body => ApplicationFlags.Body,
|
||||
EquipSlot.Hands => ApplicationFlags.Hands,
|
||||
EquipSlot.Legs => ApplicationFlags.Legs,
|
||||
EquipSlot.Feet => ApplicationFlags.Feet,
|
||||
EquipSlot.Ears => ApplicationFlags.Ears,
|
||||
EquipSlot.Neck => ApplicationFlags.Neck,
|
||||
EquipSlot.Wrists => ApplicationFlags.Wrist,
|
||||
EquipSlot.RFinger => ApplicationFlags.RFinger,
|
||||
EquipSlot.BothHand => ApplicationFlags.MainHand | ApplicationFlags.OffHand,
|
||||
EquipSlot.LFinger => ApplicationFlags.LFinger,
|
||||
EquipSlot.HeadBody => ApplicationFlags.Body,
|
||||
EquipSlot.BodyHandsLegsFeet => ApplicationFlags.Body,
|
||||
EquipSlot.LegsFeet => ApplicationFlags.Legs,
|
||||
EquipSlot.FullBody => ApplicationFlags.Body,
|
||||
EquipSlot.BodyHands => ApplicationFlags.Body,
|
||||
EquipSlot.BodyLegsFeet => ApplicationFlags.Body,
|
||||
EquipSlot.ChestHands => ApplicationFlags.Body,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
public static EquipSlot ToSlot(this ApplicationFlags flags)
|
||||
=> flags switch
|
||||
{
|
||||
ApplicationFlags.MainHand => EquipSlot.MainHand,
|
||||
ApplicationFlags.OffHand => EquipSlot.OffHand,
|
||||
ApplicationFlags.Head => EquipSlot.Head,
|
||||
ApplicationFlags.Body => EquipSlot.Body,
|
||||
ApplicationFlags.Hands => EquipSlot.Hands,
|
||||
ApplicationFlags.Legs => EquipSlot.Legs,
|
||||
ApplicationFlags.Feet => EquipSlot.Feet,
|
||||
ApplicationFlags.Ears => EquipSlot.Ears,
|
||||
ApplicationFlags.Neck => EquipSlot.Neck,
|
||||
ApplicationFlags.Wrist => EquipSlot.Wrists,
|
||||
ApplicationFlags.RFinger => EquipSlot.RFinger,
|
||||
ApplicationFlags.LFinger => EquipSlot.LFinger,
|
||||
_ => EquipSlot.Unknown,
|
||||
};
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct CharacterData
|
||||
{
|
||||
|
|
@ -153,6 +200,8 @@ public struct CharacterData
|
|||
ModelId = designable.ModelId;
|
||||
Customize.Load(designable.Customize);
|
||||
Equipment.Load(designable.Equip);
|
||||
MainHand = designable.MainHand;
|
||||
OffHand = designable.OffHand;
|
||||
Flags = SaveFlags | (designable.VisorEnabled ? ApplicationFlags.Visor : 0) | (designable.WeaponEnabled ? ApplicationFlags.Weapon : 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,6 @@ public unsafe class CurrentDesign : ICharacterData
|
|||
_drawData = _initialData.Clone();
|
||||
}
|
||||
|
||||
public void SaveCustomization(Customize customize, IReadOnlyCollection<Actor> actors)
|
||||
{
|
||||
_drawData.Customize.Load(customize);
|
||||
foreach (var actor in actors.Where(a => a && a.DrawObject))
|
||||
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _drawData.Customize);
|
||||
}
|
||||
|
||||
public void Update(Actor actor)
|
||||
{
|
||||
if (!actor)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue