mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-22 23:47:45 +01:00
Current state.
This commit is contained in:
parent
2850067f43
commit
e8c6204c25
15 changed files with 294 additions and 219 deletions
|
|
@ -100,7 +100,7 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
|
|||
|
||||
// Event NPCs have a reference to NpcEquip but also contain the appearance in their own row.
|
||||
// Prefer the NpcEquip reference if it is set and the own does not appear to be set, otherwise use the own.
|
||||
if (row.NpcEquip.RowId != 0 && row.NpcEquip.Value is { } equip && row is { ModelBody: 0, ModelLegs: 0 })
|
||||
if (row.NpcEquip.RowId is not 0 && row.NpcEquip.Value is { } equip && row is { ModelBody: 0, ModelLegs: 0 })
|
||||
ApplyNpcEquip(ref ret, equip);
|
||||
else
|
||||
ApplyNpcEquip(ref ret, row);
|
||||
|
|
@ -121,12 +121,12 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
|
|||
foreach (var baseRow in bnpcSheet)
|
||||
{
|
||||
// Only accept humans.
|
||||
if (baseRow.ModelChara.Value.Type != 1)
|
||||
if (baseRow.ModelChara.Value.Type is not 1)
|
||||
continue;
|
||||
|
||||
var bnpcNameIds = bNpcNames[baseRow.RowId];
|
||||
// Only accept battle NPCs with known associated names.
|
||||
if (bnpcNameIds.Count == 0)
|
||||
if (bnpcNameIds.Count is 0)
|
||||
continue;
|
||||
|
||||
// Check if the customization is a valid human.
|
||||
|
|
@ -186,7 +186,7 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
|
|||
}
|
||||
|
||||
// If there is only a single entry, add that.
|
||||
if (duplicates.Count == 1)
|
||||
if (duplicates.Count is 1)
|
||||
{
|
||||
_data.Add(duplicates[0]);
|
||||
Memory += 96;
|
||||
|
|
@ -200,7 +200,7 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
|
|||
|
||||
// Sort non-alphanumeric entries at the end instead of the beginning.
|
||||
var lastWeird = _data.FindIndex(d => char.IsAsciiLetterOrDigit(d.Name[0]));
|
||||
if (lastWeird != -1)
|
||||
if (lastWeird is not -1)
|
||||
{
|
||||
_data.AddRange(_data.Take(lastWeird));
|
||||
_data.RemoveRange(0, lastWeird);
|
||||
|
|
|
|||
|
|
@ -4,16 +4,13 @@ using Penumbra.GameData.Structs;
|
|||
namespace Glamourer.GameData;
|
||||
|
||||
/// <summary> A struct containing everything to replicate the appearance of a human NPC. </summary>
|
||||
public unsafe struct NpcData
|
||||
public struct NpcData
|
||||
{
|
||||
/// <summary> The name of the NPC. </summary>
|
||||
public string Name;
|
||||
|
||||
/// <summary> The customizations of the NPC. </summary>
|
||||
public CustomizeArray Customize;
|
||||
|
||||
/// <summary> The equipment appearance of the NPC, 10 * CharacterArmor. </summary>
|
||||
private fixed byte _equip[CharacterArmor.Size * 10];
|
||||
private EquipArray _equip;
|
||||
|
||||
/// <summary> The mainhand weapon appearance of the NPC. </summary>
|
||||
public CharacterWeapon Mainhand;
|
||||
|
|
@ -21,6 +18,9 @@ public unsafe struct NpcData
|
|||
/// <summary> The offhand weapon appearance of the NPC. </summary>
|
||||
public CharacterWeapon Offhand;
|
||||
|
||||
/// <summary> The customizations of the NPC. </summary>
|
||||
public CustomizeArray Customize;
|
||||
|
||||
/// <summary> The data ID of the NPC, either event NPC or battle NPC name. </summary>
|
||||
public NpcId Id;
|
||||
|
||||
|
|
@ -33,57 +33,50 @@ public unsafe struct NpcData
|
|||
/// <summary> Whether the NPC is an event NPC or a battle NPC. </summary>
|
||||
public ObjectKind Kind;
|
||||
|
||||
/// <summary> Obtain an equipment piece. </summary>
|
||||
public readonly CharacterArmor Item(int i)
|
||||
=> _equip[i];
|
||||
|
||||
/// <summary> Obtain the equipment as CharacterArmors. </summary>
|
||||
public ReadOnlySpan<CharacterArmor> Equip
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _equip)
|
||||
{
|
||||
return new ReadOnlySpan<CharacterArmor>((CharacterArmor*)ptr, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
public readonly CharacterArmor[] Equip()
|
||||
=> ((ReadOnlySpan<CharacterArmor>)_equip).ToArray();
|
||||
|
||||
/// <summary> Write all the gear appearance to a single string. </summary>
|
||||
public string WriteGear()
|
||||
{
|
||||
var sb = new StringBuilder(128);
|
||||
var span = Equip;
|
||||
var sb = new StringBuilder(256);
|
||||
|
||||
for (var i = 0; i < 10; ++i)
|
||||
{
|
||||
sb.Append(span[i].Set.Id.ToString("D4"))
|
||||
sb.Append($"{_equip[i].Set.Id:D4}")
|
||||
.Append('-')
|
||||
.Append(span[i].Variant.Id.ToString("D3"));
|
||||
foreach (var stain in span[i].Stains)
|
||||
sb.Append('-').Append(stain.Id.ToString("D3"));
|
||||
.Append($"{_equip[i].Variant.Id:D3}");
|
||||
foreach (var stain in _equip[i].Stains)
|
||||
sb.Append('-').Append($"{stain.Id:D3}");
|
||||
}
|
||||
|
||||
sb.Append(Mainhand.Skeleton.Id.ToString("D4"))
|
||||
sb.Append($"{Mainhand.Skeleton.Id:D4}")
|
||||
.Append('-')
|
||||
.Append(Mainhand.Weapon.Id.ToString("D4"))
|
||||
.Append($"{Mainhand.Weapon.Id:D4}")
|
||||
.Append('-')
|
||||
.Append(Mainhand.Variant.Id.ToString("D3"));
|
||||
.Append($"{Mainhand.Variant.Id:D3}");
|
||||
foreach (var stain in Mainhand.Stains)
|
||||
sb.Append('-').Append(stain.Id.ToString("D3"));
|
||||
sb.Append('-').Append($"{stain.Id:D3}");
|
||||
sb.Append(", ")
|
||||
.Append(Offhand.Skeleton.Id.ToString("D4"))
|
||||
.Append($"{Offhand.Skeleton.Id:D4}")
|
||||
.Append('-')
|
||||
.Append(Offhand.Weapon.Id.ToString("D4"))
|
||||
.Append($"{Offhand.Weapon.Id:D4}")
|
||||
.Append('-')
|
||||
.Append(Offhand.Variant.Id.ToString("D3"));
|
||||
.Append($"{Offhand.Variant.Id:D3}");
|
||||
foreach (var stain in Mainhand.Stains)
|
||||
sb.Append('-').Append(stain.Id.ToString("D3"));
|
||||
sb.Append('-').Append($"{stain.Id:D3}");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary> Set an equipment piece to a given value. </summary>
|
||||
internal void Set(int idx, ulong value)
|
||||
{
|
||||
fixed (byte* ptr = _equip)
|
||||
{
|
||||
((ulong*)ptr)[idx] = value;
|
||||
}
|
||||
_equip[idx] = Unsafe.As<ulong, CharacterArmor>(ref value);
|
||||
}
|
||||
|
||||
/// <summary> Check if the appearance data, excluding ID and Name, of two NpcData is equal. </summary>
|
||||
|
|
@ -104,9 +97,12 @@ public unsafe struct NpcData
|
|||
if (!Offhand.Equals(other.Offhand))
|
||||
return false;
|
||||
|
||||
fixed (byte* ptr1 = _equip, ptr2 = other._equip)
|
||||
{
|
||||
return new ReadOnlySpan<byte>(ptr1, 40).SequenceEqual(new ReadOnlySpan<byte>(ptr2, 40));
|
||||
}
|
||||
return ((ReadOnlySpan<CharacterArmor>)_equip).SequenceEqual(other._equip);
|
||||
}
|
||||
|
||||
[InlineArray(10)]
|
||||
private struct EquipArray
|
||||
{
|
||||
private CharacterArmor _element;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,80 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using Lumina.Excel.Sheets;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Addon = Lumina.Excel.Sheets.Addon;
|
||||
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public sealed class BonusItemCombo2(IDataManager gameData, ItemManager items, FavoriteManager favorites, BonusItemFlag slot)
|
||||
: ImSharp.FilterComboBase<BonusItemCombo2.CacheItem>(new ItemFilter())
|
||||
{
|
||||
public readonly StringU8 Label = GetLabel(gameData, slot);
|
||||
public readonly BonusItemFlag Slot = slot;
|
||||
|
||||
public readonly struct CacheItem(EquipItem item) : IDisposable
|
||||
{
|
||||
public readonly EquipItem Item = item;
|
||||
public readonly StringPair Name = new(item.Name);
|
||||
public readonly SizedString Model = new($"({item.PrimaryId.Id}-{item.Variant.Id})");
|
||||
|
||||
public void Dispose()
|
||||
=> Model.Dispose();
|
||||
}
|
||||
|
||||
private sealed class ItemFilter : PartwiseFilterBase<CacheItem>
|
||||
{
|
||||
protected override string ToFilterString(in CacheItem item, int globalIndex)
|
||||
=> item.Name.Utf16;
|
||||
}
|
||||
|
||||
protected override IEnumerable<CacheItem> GetItems()
|
||||
{
|
||||
var nothing = EquipItem.BonusItemNothing(Slot);
|
||||
return items.ItemData.ByType[Slot.ToEquipType()].OrderByDescending(favorites.Contains).ThenBy(i => i.Id.Id).Prepend(nothing)
|
||||
.Select(i => new CacheItem(i));
|
||||
}
|
||||
|
||||
protected override float ItemHeight
|
||||
=> Im.Style.TextHeightWithSpacing;
|
||||
|
||||
protected override bool DrawItem(in CacheItem item, int globalIndex, bool selected)
|
||||
{
|
||||
UiHelpers.DrawFavoriteStar(favorites, item.Item);
|
||||
Im.Line.Same();
|
||||
var ret = Im.Selectable(item.Name.Utf8, selected);
|
||||
Im.Line.Same();
|
||||
using var color = ImGuiColor.Text.Push(Rgba32.Gray);
|
||||
ImEx.TextRightAligned(item.Model);
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override bool IsSelected(CacheItem item, int globalIndex)
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
private static StringU8 GetLabel(IDataManager gameData, BonusItemFlag slot)
|
||||
{
|
||||
var sheet = gameData.GetExcelSheet<Addon>()!;
|
||||
|
||||
return slot switch
|
||||
{
|
||||
BonusItemFlag.Glasses => sheet.TryGetRow(16050, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Facewear"u8),
|
||||
BonusItemFlag.UnkSlot => sheet.TryGetRow(16051, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Facewear"u8),
|
||||
|
||||
_ => StringU8.Empty,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BonusItemCombo : FilterComboCache<EquipItem>
|
||||
{
|
||||
private readonly FavoriteManager _favorites;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using Lumina.Excel.Sheets;
|
|||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public sealed class MainWindow : Window, IDisposable
|
|||
SizeConstraints = new WindowSizeConstraints
|
||||
{
|
||||
MinimumSize = new Vector2(700, 675),
|
||||
MaximumSize = Im.Io.DisplaySize,
|
||||
MaximumSize = new Vector2(3840, 2160),
|
||||
};
|
||||
_mainTabBar = mainTabBar;
|
||||
_quickBar = quickBar;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Glamourer.State;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
|
@ -14,20 +14,20 @@ public sealed class FunPanel(FunModule funModule, Configuration config) : IGameD
|
|||
|
||||
public void Draw()
|
||||
{
|
||||
ImGui.TextUnformatted($"Current Festival: {funModule.CurrentFestival}");
|
||||
ImGui.TextUnformatted($"Festivals Enabled: {config.DisableFestivals switch { 1 => "Undecided", 0 => "Enabled", _ => "Disabled" }}");
|
||||
ImGui.TextUnformatted($"Popup Open: {ImGui.IsPopupOpen("FestivalPopup", ImGuiPopupFlags.AnyPopup)}");
|
||||
if (ImGui.Button("Force Christmas"))
|
||||
Im.Text($"Current Festival: {funModule.CurrentFestival}");
|
||||
Im.Text($"Festivals Enabled: {config.DisableFestivals switch { 1 => "Undecided"u8, 0 => "Enabled"u8, _ => "Disabled"u8 }}");
|
||||
Im.Text($"Popup Open: {Im.Popup.IsOpen("FestivalPopup"u8, PopupQueryFlags.AnyPopup)}");
|
||||
if (Im.Button("Force Christmas"u8))
|
||||
funModule.ForceFestival(FunModule.FestivalType.Christmas);
|
||||
if (ImGui.Button("Force Halloween"))
|
||||
if (Im.Button("Force Halloween"u8))
|
||||
funModule.ForceFestival(FunModule.FestivalType.Halloween);
|
||||
if (ImGui.Button("Force April First"))
|
||||
if (Im.Button("Force April First"u8))
|
||||
funModule.ForceFestival(FunModule.FestivalType.AprilFirst);
|
||||
if (ImGui.Button("Force None"))
|
||||
if (Im.Button("Force None"u8))
|
||||
funModule.ForceFestival(FunModule.FestivalType.None);
|
||||
if (ImGui.Button("Revert"))
|
||||
if (Im.Button("Revert"u8))
|
||||
funModule.ResetFestival();
|
||||
if (ImGui.Button("Reset Popup"))
|
||||
if (Im.Button("Reset Popup"u8))
|
||||
{
|
||||
config.DisableFestivals = 1;
|
||||
config.Save();
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
using Dalamud.Interface.Utility.Raii;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
|
@ -43,29 +39,29 @@ public sealed unsafe class GlamourPlatePanel : IGameDataDrawer
|
|||
public void Draw()
|
||||
{
|
||||
var manager = MirageManager.Instance();
|
||||
using (ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
ImUtf8.Text("Address:"u8);
|
||||
ImUtf8.Text("Number of Glamour Plates:"u8);
|
||||
ImUtf8.Text("Glamour Plates Requested:"u8);
|
||||
ImUtf8.Text("Glamour Plates Loaded:"u8);
|
||||
ImUtf8.Text("Is Applying Glamour Plates:"u8);
|
||||
Im.Text("Address:"u8);
|
||||
Im.Text("Number of Glamour Plates:"u8);
|
||||
Im.Text("Glamour Plates Requested:"u8);
|
||||
Im.Text("Glamour Plates Loaded:"u8);
|
||||
Im.Text("Is Applying Glamour Plates:"u8);
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
using (ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)manager:X}");
|
||||
ImUtf8.Text(manager == null ? "-" : manager->GlamourPlates.Length.ToString());
|
||||
ImUtf8.Text(manager == null ? "-" : manager->GlamourPlatesRequested.ToString());
|
||||
Glamourer.Dynamis.DrawPointer(manager);
|
||||
Im.Text(manager is null ? "-"u8 : $"{manager->GlamourPlates.Length}");
|
||||
Im.Text(manager is null ? "-"u8 : $"{manager->GlamourPlatesRequested}");
|
||||
Im.Line.Same();
|
||||
if (Im.SmallButton("Request Update"u8))
|
||||
RequestGlamour();
|
||||
ImUtf8.Text(manager == null ? "-" : manager->GlamourPlatesLoaded.ToString());
|
||||
ImUtf8.Text(manager == null ? "-" : manager->IsApplyingGlamourPlate.ToString());
|
||||
Im.Text(manager is null ? "-"u8 : $"{manager->GlamourPlatesLoaded}");
|
||||
Im.Text(manager is null ? "-"u8 : $"{manager->IsApplyingGlamourPlate}");
|
||||
}
|
||||
|
||||
if (manager == null)
|
||||
if (manager is null)
|
||||
return;
|
||||
|
||||
ActorState? state = null;
|
||||
|
|
@ -74,28 +70,28 @@ public sealed unsafe class GlamourPlatePanel : IGameDataDrawer
|
|||
|
||||
for (var i = 0; i < manager->GlamourPlates.Length; ++i)
|
||||
{
|
||||
using var tree = ImUtf8.TreeNode($"Plate #{i + 1:D2}");
|
||||
using var tree = Im.Tree.Node($"Plate #{i + 1:D2}");
|
||||
if (!tree)
|
||||
continue;
|
||||
|
||||
ref var plate = ref manager->GlamourPlates[i];
|
||||
if (ImUtf8.ButtonEx("Apply to Player"u8, ""u8, Vector2.Zero, !enabled))
|
||||
if (ImEx.Button("Apply to Player"u8, Vector2.Zero, StringU8.Empty, !enabled))
|
||||
{
|
||||
var design = CreateDesign(plate);
|
||||
_state.ApplyDesign(state!, design, ApplySettings.Manual with { IsFinal = true });
|
||||
}
|
||||
|
||||
using (ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
foreach (var slot in EquipSlotExtensions.FullSlots)
|
||||
ImUtf8.Text(slot.ToName());
|
||||
Im.Text(slot.ToNameU8());
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
using (ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
foreach (var (_, index) in EquipSlotExtensions.FullSlots.WithIndex())
|
||||
ImUtf8.Text($"{plate.ItemIds[index]:D6}, {StainIds.FromGlamourPlate(plate, index)}");
|
||||
foreach (var (index, _) in EquipSlotExtensions.FullSlots.Index())
|
||||
Im.Text($"{plate.ItemIds[index]:D6}, {StainIds.FromGlamourPlate(plate, index)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -106,7 +102,7 @@ public sealed unsafe class GlamourPlatePanel : IGameDataDrawer
|
|||
public void RequestGlamour()
|
||||
{
|
||||
var manager = MirageManager.Instance();
|
||||
if (manager == null)
|
||||
if (manager is null)
|
||||
return;
|
||||
|
||||
_requestUpdate(manager);
|
||||
|
|
@ -116,10 +112,10 @@ public sealed unsafe class GlamourPlatePanel : IGameDataDrawer
|
|||
{
|
||||
var design = _design.CreateTemporary();
|
||||
design.Application = ApplicationCollection.None;
|
||||
foreach (var (slot, index) in EquipSlotExtensions.FullSlots.WithIndex())
|
||||
foreach (var (index, slot) in EquipSlotExtensions.FullSlots.Index())
|
||||
{
|
||||
var itemId = plate.ItemIds[index];
|
||||
if (itemId == 0)
|
||||
if (itemId is 0)
|
||||
continue;
|
||||
|
||||
var item = _items.Resolve(slot, itemId);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
|
@ -18,16 +15,16 @@ public sealed unsafe class InventoryPanel : IGameDataDrawer
|
|||
public void Draw()
|
||||
{
|
||||
var inventory = InventoryManager.Instance();
|
||||
if (inventory == null)
|
||||
if (inventory is null)
|
||||
return;
|
||||
|
||||
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)inventory:X}");
|
||||
Glamourer.Dynamis.DrawPointer(inventory);
|
||||
|
||||
var equip = inventory->GetInventoryContainer(InventoryType.EquippedItems);
|
||||
if (equip == null || equip->IsLoaded)
|
||||
if (equip is null || equip->IsLoaded)
|
||||
return;
|
||||
|
||||
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)equip:X}");
|
||||
Glamourer.Dynamis.DrawPointer(equip);
|
||||
|
||||
using var table = Im.Table.Begin("items"u8, 4, TableFlags.RowBackground | TableFlags.SizingFixedFit);
|
||||
if (!table)
|
||||
|
|
@ -35,19 +32,19 @@ public sealed unsafe class InventoryPanel : IGameDataDrawer
|
|||
|
||||
for (var i = 0; i < equip->Size; ++i)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(i.ToString());
|
||||
table.DrawColumn($"{i}");
|
||||
var item = equip->GetInventorySlot(i);
|
||||
if (item == null)
|
||||
if (item is null)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn("NULL");
|
||||
ImGui.TableNextRow();
|
||||
table.DrawColumn("NULL"u8);
|
||||
table.NextRow();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(item->ItemId.ToString());
|
||||
ImGuiUtil.DrawTableColumn(item->GlamourId.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)item:X}");
|
||||
table.DrawColumn($"{item->ItemId}");
|
||||
table.DrawColumn($"{item->GlamourId}");
|
||||
table.NextColumn();
|
||||
Glamourer.Dynamis.DrawPointer(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
|
|
@ -32,31 +28,28 @@ public sealed class ItemUnlockPanel(ItemUnlockManager itemUnlocks, ItemManager i
|
|||
table.SetupColumn("Model"u8, TableColumnFlags.WidthFixed, 80 * Im.Style.GlobalScale);
|
||||
table.SetupColumn("Unlock"u8, TableColumnFlags.WidthFixed, 120 * Im.Style.GlobalScale);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(Im.Style.TextHeightWithSpacing);
|
||||
ImGui.TableNextRow();
|
||||
var remainder = ImGuiClip.ClippedDraw(itemUnlocks, skips, t =>
|
||||
using var clipper = new Im.ListClipper(itemUnlocks.Count, Im.Style.TextHeightWithSpacing);
|
||||
foreach (var (id, _) in clipper.Iterate(itemUnlocks))
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
||||
if (items.ItemData.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||
table.DrawColumn($"{id}");
|
||||
if (items.ItemData.TryGetValue(id, EquipSlot.MainHand, out var equip))
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(equip.Name);
|
||||
ImGuiUtil.DrawTableColumn(equip.Type.ToName());
|
||||
ImGuiUtil.DrawTableColumn(equip.Weapon().ToString());
|
||||
table.DrawColumn(equip.Name);
|
||||
table.DrawColumn(equip.Type.ToName());
|
||||
table.DrawColumn($"{equip.Weapon()}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
table.NextColumn();
|
||||
table.NextColumn();
|
||||
table.NextColumn();
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn(itemUnlocks.IsUnlocked(t.Key, out var time)
|
||||
table.DrawColumn(itemUnlocks.IsUnlocked(id, out var time)
|
||||
? time == DateTimeOffset.MinValue
|
||||
? "Always"
|
||||
: time.LocalDateTime.ToString("g")
|
||||
: "Never");
|
||||
}, itemUnlocks.Count);
|
||||
ImGuiClip.DrawEndDummy(remainder, Im.Style.TextHeight);
|
||||
? "Always"u8
|
||||
: $"{time.LocalDateTime:g}"
|
||||
: "Never"u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.State;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public sealed class NpcAppearancePanel(NpcCombo npcCombo, StateManager stateManager, ActorObjectManager objectManager, DesignConverter designConverter)
|
||||
public sealed class NpcAppearancePanel(
|
||||
NpcCustomizeSet npcData,
|
||||
StateManager stateManager,
|
||||
ActorObjectManager objectManager,
|
||||
DesignConverter designConverter)
|
||||
: IGameDataDrawer
|
||||
{
|
||||
public ReadOnlySpan<byte> Label
|
||||
|
|
@ -24,23 +24,45 @@ public sealed class NpcAppearancePanel(NpcCombo npcCombo, StateManager stateMana
|
|||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private string _npcFilter = string.Empty;
|
||||
private bool _customizeOrGear;
|
||||
private readonly NpcDataFilter _filter = new();
|
||||
private bool _customizeOrGear;
|
||||
|
||||
private sealed class NpcDataFilter : TextFilterBase<CacheItem>
|
||||
{
|
||||
protected override string ToFilterString(in CacheItem item, int globalIndex)
|
||||
=> item.Name.Utf16;
|
||||
}
|
||||
|
||||
private readonly struct CacheItem(NpcData data)
|
||||
{
|
||||
public readonly NpcData Data = data;
|
||||
public readonly StringPair Name = new(data.Name);
|
||||
public readonly StringU8 DataId = new($"{data.Id.Id}");
|
||||
public readonly StringU8 ModelId = new($"{data.ModelId}");
|
||||
public readonly AwesomeIcon Visor = data.VisorToggled ? LunaStyle.TrueIcon : LunaStyle.FalseIcon;
|
||||
public readonly StringU8 CustomizeData = new($"{data.Customize}");
|
||||
public readonly StringU8 GearData = StringU8.Empty; //new(data.WriteGear());
|
||||
}
|
||||
|
||||
private sealed class Cache(NpcCustomizeSet npcData, NpcDataFilter filter) : BasicFilterCache<CacheItem>(filter)
|
||||
{
|
||||
protected override IEnumerable<CacheItem> GetItems()
|
||||
=> npcData.Select(i => new CacheItem(i));
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
ImUtf8.Checkbox("Compare Customize (or Gear)"u8, ref _customizeOrGear);
|
||||
ImGui.SetNextItemWidth(Im.ContentRegion.Available.X);
|
||||
var resetScroll = ImUtf8.InputText("##npcFilter"u8, ref _npcFilter, "Filter..."u8);
|
||||
Im.Checkbox("Compare Customize (or Gear)"u8, ref _customizeOrGear);
|
||||
var resetScroll = _filter.DrawFilter("Filter..."u8, Im.ContentRegion.Available);
|
||||
|
||||
using var table = Im.Table.Begin("npcs"u8, 7, TableFlags.RowBackground | TableFlags.ScrollY | TableFlags.SizingFixedFit,
|
||||
new Vector2(-1, 400 * Im.Style.GlobalScale));
|
||||
Im.ContentRegion.Available with { Y = 400 * Im.Style.GlobalScale });
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
|
||||
if (resetScroll)
|
||||
ImGui.SetScrollY(0);
|
||||
|
||||
Im.Scroll.Y = 0;
|
||||
|
||||
table.SetupColumn("Button"u8, TableColumnFlags.WidthFixed);
|
||||
table.SetupColumn("Name"u8, TableColumnFlags.WidthFixed, Im.Style.GlobalScale * 300);
|
||||
table.SetupColumn("Kind"u8, TableColumnFlags.WidthFixed);
|
||||
|
|
@ -48,45 +70,30 @@ public sealed class NpcAppearancePanel(NpcCombo npcCombo, StateManager stateMana
|
|||
table.SetupColumn("Model"u8, TableColumnFlags.WidthFixed);
|
||||
table.SetupColumn("Visor"u8, TableColumnFlags.WidthFixed);
|
||||
table.SetupColumn("Compare"u8, TableColumnFlags.WidthStretch);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(Im.Style.FrameHeightWithSpacing);
|
||||
ImGui.TableNextRow();
|
||||
var idx = 0;
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(npcCombo.Items, skips,
|
||||
d => d.Name.Contains(_npcFilter, StringComparison.OrdinalIgnoreCase), DrawData);
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiClip.DrawEndDummy(remainder, Im.Style.FrameHeightWithSpacing);
|
||||
return;
|
||||
|
||||
void DrawData(NpcData data)
|
||||
|
||||
var cache = CacheManager.Instance.GetOrCreateCache(Im.Id.Current, () => new Cache(npcData, _filter));
|
||||
using var clipper = new Im.ListClipper(cache.Count, Im.Style.FrameHeightWithSpacing);
|
||||
foreach (var (idx, data) in clipper.Iterate(cache).Index())
|
||||
{
|
||||
using var id = Im.Id.Push(idx++);
|
||||
using var id = Im.Id.Push(idx);
|
||||
var disabled = !stateManager.GetOrCreate(objectManager.Player, out var state);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImUtf8.ButtonEx("Apply"u8, ""u8, Vector2.Zero, disabled))
|
||||
table.NextColumn();
|
||||
if (ImEx.Button("Apply"u8, Vector2.Zero, StringU8.Empty, disabled))
|
||||
{
|
||||
foreach (var (slot, item, stain) in designConverter.FromDrawData(data.Equip.ToArray(), data.Mainhand, data.Offhand, true))
|
||||
foreach (var (slot, item, stain) in designConverter.FromDrawData(data.Data.Equip(), data.Data.Mainhand, data.Data.Offhand, true))
|
||||
stateManager.ChangeEquip(state!, slot, item, stain, ApplySettings.Manual);
|
||||
stateManager.ChangeMetaState(state!, MetaIndex.VisorState, data.VisorToggled, ApplySettings.Manual);
|
||||
stateManager.ChangeEntireCustomize(state!, data.Customize, CustomizeFlagExtensions.All, ApplySettings.Manual);
|
||||
}
|
||||
|
||||
ImUtf8.DrawFrameColumn(data.Name);
|
||||
|
||||
ImUtf8.DrawFrameColumn(data.Kind is ObjectKind.BattleNpc ? "B" : "E");
|
||||
|
||||
ImUtf8.DrawFrameColumn(data.Id.Id.ToString());
|
||||
|
||||
ImUtf8.DrawFrameColumn(data.ModelId.ToString());
|
||||
|
||||
using (_ = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImUtf8.DrawFrameColumn(data.VisorToggled ? FontAwesomeIcon.Check.ToIconString() : FontAwesomeIcon.Times.ToIconString());
|
||||
stateManager.ChangeMetaState(state!, MetaIndex.VisorState, data.Data.VisorToggled, ApplySettings.Manual);
|
||||
stateManager.ChangeEntireCustomize(state!, data.Data.Customize, CustomizeFlagExtensions.All, ApplySettings.Manual);
|
||||
}
|
||||
|
||||
table.DrawFrameColumn(data.Name.Utf8);
|
||||
table.DrawFrameColumn(data.Data.Kind is ObjectKind.BattleNpc ? "B"u8 : "E"u8);
|
||||
table.DrawFrameColumn(data.DataId);
|
||||
table.DrawFrameColumn(data.ModelId);
|
||||
table.NextColumn();
|
||||
ImEx.Icon.DrawAligned(data.Visor);
|
||||
using var mono = Im.Font.PushMono();
|
||||
ImUtf8.DrawFrameColumn(_customizeOrGear ? data.Customize.ToString() : data.WriteGear());
|
||||
table.DrawFrameColumn(_customizeOrGear ? data.CustomizeData : data.GearData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using OtterGui;
|
||||
using OtterGui.Text;
|
||||
using ImSharp;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
|
@ -16,7 +13,44 @@ public sealed class ObjectManagerPanel(ActorObjectManager objectManager, ActorMa
|
|||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private string _objectFilter = string.Empty;
|
||||
private sealed class Filter : TextFilterBase<CacheItem>
|
||||
{
|
||||
protected override string ToFilterString(in CacheItem item, int globalIndex)
|
||||
=> item.Label.Utf16;
|
||||
}
|
||||
|
||||
private readonly struct CacheItem(ActorIdentifier identifier, ActorData data)
|
||||
{
|
||||
public readonly StringPair Label = new(data.Label);
|
||||
public readonly StringU8 Name = new($"{identifier}");
|
||||
public readonly StringU8 Objects = StringU8.Join(", "u8, data.Objects.OrderBy(a => a.Index).Select(a => a.Index));
|
||||
}
|
||||
|
||||
private sealed class Cache : BasicFilterCache<CacheItem>
|
||||
{
|
||||
private readonly ActorObjectManager _objectManager;
|
||||
|
||||
public Cache(ActorObjectManager objectManager, Filter filter)
|
||||
: base(filter)
|
||||
{
|
||||
_objectManager = objectManager;
|
||||
_objectManager.Objects.OnUpdate += OnUpdate;
|
||||
}
|
||||
|
||||
private void OnUpdate()
|
||||
=> Dirty |= IManagedCache.DirtyFlags.Custom;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
_objectManager.Objects.OnUpdate -= OnUpdate;
|
||||
}
|
||||
|
||||
protected override IEnumerable<CacheItem> GetItems()
|
||||
=> _objectManager.Select(o => new CacheItem(o.Key, o.Value));
|
||||
}
|
||||
|
||||
private readonly Filter _filter = new();
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
|
|
@ -27,58 +61,52 @@ public sealed class ObjectManagerPanel(ActorObjectManager objectManager, ActorMa
|
|||
if (!table)
|
||||
return;
|
||||
|
||||
ImUtf8.DrawTableColumn("World"u8);
|
||||
ImUtf8.DrawTableColumn(actors.Finished ? actors.Data.ToWorldName(objectManager.World) : "Service Missing");
|
||||
ImUtf8.DrawTableColumn(objectManager.World.ToString());
|
||||
table.DrawColumn("World"u8);
|
||||
table.DrawColumn(actors.Finished ? actors.Data.ToWorldName(objectManager.World) : "Service Missing"u8);
|
||||
table.DrawColumn($"{objectManager.World}");
|
||||
|
||||
ImUtf8.DrawTableColumn("Player Character"u8);
|
||||
ImUtf8.DrawTableColumn($"{objectManager.Player.Utf8Name} ({objectManager.Player.Index})");
|
||||
ImGui.TableNextColumn();
|
||||
ImUtf8.CopyOnClickSelectable(objectManager.Player.ToString());
|
||||
table.DrawColumn("Player Character"u8);
|
||||
table.DrawColumn($"{objectManager.Player.Utf8Name} ({objectManager.Player.Index})");
|
||||
table.NextColumn();
|
||||
Glamourer.Dynamis.DrawPointer(objectManager.Player.Address);
|
||||
|
||||
ImUtf8.DrawTableColumn("In GPose"u8);
|
||||
ImUtf8.DrawTableColumn(objectManager.IsInGPose.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
table.DrawColumn("In GPose"u8);
|
||||
table.DrawColumn($"{objectManager.IsInGPose}");
|
||||
table.NextColumn();
|
||||
|
||||
ImUtf8.DrawTableColumn("In Lobby"u8);
|
||||
ImUtf8.DrawTableColumn(objectManager.IsInLobby.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
table.DrawColumn("In Lobby"u8);
|
||||
table.DrawColumn($"{objectManager.IsInLobby}");
|
||||
table.NextColumn();
|
||||
|
||||
if (objectManager.IsInGPose)
|
||||
{
|
||||
ImUtf8.DrawTableColumn("GPose Player"u8);
|
||||
ImUtf8.DrawTableColumn($"{objectManager.GPosePlayer.Utf8Name} ({objectManager.GPosePlayer.Index})");
|
||||
ImGui.TableNextColumn();
|
||||
ImUtf8.CopyOnClickSelectable(objectManager.GPosePlayer.ToString());
|
||||
table.DrawColumn("GPose Player"u8);
|
||||
table.DrawColumn($"{objectManager.GPosePlayer.Utf8Name} ({objectManager.GPosePlayer.Index})");
|
||||
table.NextColumn();
|
||||
Glamourer.Dynamis.DrawPointer(objectManager.GPosePlayer.Address);
|
||||
}
|
||||
|
||||
ImUtf8.DrawTableColumn("Number of Players"u8);
|
||||
ImUtf8.DrawTableColumn(objectManager.Count.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
table.DrawColumn("Number of Players"u8);
|
||||
table.DrawColumn($"{objectManager.Count}");
|
||||
table.NextColumn();
|
||||
}
|
||||
|
||||
var filterChanged = ImUtf8.InputText("##Filter"u8, ref _objectFilter, "Filter..."u8);
|
||||
using var table2 = Im.Table.Begin("##data2"u8, 3,
|
||||
TableFlags.RowBackground | TableFlags.BordersOuter | TableFlags.ScrollY,
|
||||
new Vector2(-1, 20 * Im.Style.TextHeightWithSpacing));
|
||||
var filterChanged = _filter.DrawFilter("Filter..."u8, Im.ContentRegion.Available);
|
||||
using var table2 = Im.Table.Begin("##data2"u8, 3, TableFlags.RowBackground | TableFlags.BordersOuter | TableFlags.ScrollY,
|
||||
Im.ContentRegion.Available with { Y = 20 * Im.Style.TextHeightWithSpacing });
|
||||
if (!table2)
|
||||
return;
|
||||
|
||||
if (filterChanged)
|
||||
ImGui.SetScrollY(0);
|
||||
Im.Scroll.Y = 0;
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(Im.Style.TextHeightWithSpacing);
|
||||
ImGui.TableNextRow();
|
||||
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(objectManager, skips,
|
||||
p => p.Value.Label.Contains(_objectFilter, StringComparison.OrdinalIgnoreCase), p
|
||||
=>
|
||||
{
|
||||
ImUtf8.DrawTableColumn(p.Key.ToString());
|
||||
ImUtf8.DrawTableColumn(p.Value.Label);
|
||||
ImUtf8.DrawTableColumn(string.Join(", ", p.Value.Objects.OrderBy(a => a.Index).Select(a => a.Index.ToString())));
|
||||
});
|
||||
ImGuiClip.DrawEndDummy(remainder, Im.Style.TextHeightWithSpacing);
|
||||
var cache = CacheManager.Instance.GetOrCreateCache(Im.Id.Current, () => new Cache(objectManager, _filter));
|
||||
using var clip = new Im.ListClipper(cache.Count, Im.Style.TextHeightWithSpacing);
|
||||
foreach (var item in clip.Iterate(cache))
|
||||
{
|
||||
table2.DrawColumn(item.Name);
|
||||
table2.DrawColumn(item.Label.Utf8);
|
||||
table2.DrawColumn(item.Objects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ public class NpcPanel
|
|||
private DesignData ToDesignData()
|
||||
{
|
||||
var selection = _selector.Selection;
|
||||
var items = _converter.FromDrawData(selection.Equip.ToArray(), selection.Mainhand, selection.Offhand, true).ToArray();
|
||||
var items = _converter.FromDrawData(selection.Equip(), selection.Mainhand, selection.Offhand, true).ToArray();
|
||||
var designData = new DesignData { Customize = selection.Customize };
|
||||
foreach (var (slot, item, stain) in items)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ public sealed class UnlocksTab : Window, ITab<MainTabType>
|
|||
IsOpen = false;
|
||||
SizeConstraints = new WindowSizeConstraints
|
||||
{
|
||||
MinimumSize = new Vector2(700, 675),
|
||||
MaximumSize = Im.Io.DisplaySize,
|
||||
MinimumSize = new Vector2(700, 675),
|
||||
MaximumSize = new Vector2(3840, 2160),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ public unsafe class FunModule : IDisposable
|
|||
customize = npc.Customize;
|
||||
var idx = 0;
|
||||
foreach (ref var a in armor)
|
||||
a = npc.Equip[idx++];
|
||||
a = npc.Item(idx++);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit b5213e2dee715bb6c53dc15dee61392b183a34a1
|
||||
Subproject commit 478febd4ed9af42055ce7396f69cec0334bc4140
|
||||
Loading…
Add table
Add a link
Reference in a new issue