mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Rework debug tab.
This commit is contained in:
parent
a04b7cd1db
commit
4b92eae723
31 changed files with 2450 additions and 1790 deletions
|
|
@ -1,14 +1,234 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.GameData;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
public static class CustomizationNpcOptions
|
||||
{
|
||||
public unsafe struct NpcData
|
||||
{
|
||||
public string Name;
|
||||
public Customize Customize;
|
||||
private fixed byte _equip[40];
|
||||
public CharacterWeapon Mainhand;
|
||||
public CharacterWeapon Offhand;
|
||||
public uint Id;
|
||||
public bool VisorToggled;
|
||||
public ObjectKind Kind;
|
||||
|
||||
public ReadOnlySpan<CharacterArmor> Equip
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _equip)
|
||||
{
|
||||
return new ReadOnlySpan<CharacterArmor>((CharacterArmor*)ptr, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string WriteGear()
|
||||
{
|
||||
var sb = new StringBuilder(128);
|
||||
var span = Equip;
|
||||
for (var i = 0; i < 10; ++i)
|
||||
{
|
||||
sb.Append(span[i].Set.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(span[i].Variant.Id.ToString("D3"));
|
||||
sb.Append('-');
|
||||
sb.Append(span[i].Stain.Id.ToString("D3"));
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append(Mainhand.Set.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Mainhand.Type.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Mainhand.Variant.Id.ToString("D3"));
|
||||
sb.Append('-');
|
||||
sb.Append(Mainhand.Stain.Id.ToString("D4"));
|
||||
sb.Append(", ");
|
||||
sb.Append(Offhand.Set.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Offhand.Type.Id.ToString("D4"));
|
||||
sb.Append('-');
|
||||
sb.Append(Offhand.Variant.Id.ToString("D3"));
|
||||
sb.Append('-');
|
||||
sb.Append(Offhand.Stain.Id.ToString("D3"));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal void Set(int idx, uint value)
|
||||
{
|
||||
fixed (byte* ptr = _equip)
|
||||
{
|
||||
((uint*)ptr)[idx] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool DataEquals(in NpcData other)
|
||||
{
|
||||
if (VisorToggled != other.VisorToggled)
|
||||
return false;
|
||||
|
||||
if (!Customize.Equals(other.Customize))
|
||||
return false;
|
||||
|
||||
if (!Mainhand.Equals(other.Mainhand))
|
||||
return false;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyNpcEquip(ref NpcData data, NpcEquip row)
|
||||
{
|
||||
data.Set(0, row.ModelHead | (row.DyeHead.Row << 24));
|
||||
data.Set(1, row.ModelBody | (row.DyeBody.Row << 24));
|
||||
data.Set(2, row.ModelHands | (row.DyeHands.Row << 24));
|
||||
data.Set(3, row.ModelLegs | (row.DyeLegs.Row << 24));
|
||||
data.Set(4, row.ModelFeet | (row.DyeFeet.Row << 24));
|
||||
data.Set(5, row.ModelEars | (row.DyeEars.Row << 24));
|
||||
data.Set(6, row.ModelNeck | (row.DyeNeck.Row << 24));
|
||||
data.Set(7, row.ModelWrists | (row.DyeWrists.Row << 24));
|
||||
data.Set(8, row.ModelRightRing | (row.DyeRightRing.Row << 24));
|
||||
data.Set(9, row.ModelLeftRing | (row.DyeLeftRing.Row << 24));
|
||||
data.Mainhand = new CharacterWeapon(row.ModelMainHand | ((ulong)row.DyeMainHand.Row << 48));
|
||||
data.Offhand = new CharacterWeapon(row.ModelOffHand | ((ulong)row.DyeOffHand.Row << 48));
|
||||
data.VisorToggled = row.Visor;
|
||||
}
|
||||
|
||||
public static unsafe IReadOnlyList<NpcData> CreateNpcData(IReadOnlyDictionary<uint, string> eNpcs,
|
||||
IReadOnlyDictionary<uint, string> bnpcNames, IObjectIdentifier identifier, IDataManager data)
|
||||
{
|
||||
var enpcSheet = data.GetExcelSheet<ENpcBase>()!;
|
||||
var bnpcSheet = data.GetExcelSheet<BNpcBase>()!;
|
||||
var list = new List<NpcData>(eNpcs.Count + (int)bnpcSheet.RowCount);
|
||||
foreach (var (id, name) in eNpcs)
|
||||
{
|
||||
var row = enpcSheet.GetRow(id);
|
||||
if (row == null || name.IsNullOrWhitespace())
|
||||
continue;
|
||||
|
||||
var (valid, customize) = FromEnpcBase(row);
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
var ret = new NpcData
|
||||
{
|
||||
Name = name,
|
||||
Customize = customize,
|
||||
Id = id,
|
||||
Kind = ObjectKind.EventNpc,
|
||||
};
|
||||
|
||||
if (row.NpcEquip.Row != 0 && row.NpcEquip.Value is { } equip)
|
||||
{
|
||||
ApplyNpcEquip(ref ret, equip);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Set(0, row.ModelHead | (row.DyeHead.Row << 24));
|
||||
ret.Set(1, row.ModelBody | (row.DyeBody.Row << 24));
|
||||
ret.Set(2, row.ModelHands | (row.DyeHands.Row << 24));
|
||||
ret.Set(3, row.ModelLegs | (row.DyeLegs.Row << 24));
|
||||
ret.Set(4, row.ModelFeet | (row.DyeFeet.Row << 24));
|
||||
ret.Set(5, row.ModelEars | (row.DyeEars.Row << 24));
|
||||
ret.Set(6, row.ModelNeck | (row.DyeNeck.Row << 24));
|
||||
ret.Set(7, row.ModelWrists | (row.DyeWrists.Row << 24));
|
||||
ret.Set(8, row.ModelRightRing | (row.DyeRightRing.Row << 24));
|
||||
ret.Set(9, row.ModelLeftRing | (row.DyeLeftRing.Row << 24));
|
||||
ret.Mainhand = new CharacterWeapon(row.ModelMainHand | ((ulong)row.DyeMainHand.Row << 48));
|
||||
ret.Offhand = new CharacterWeapon(row.ModelOffHand | ((ulong)row.DyeOffHand.Row << 48));
|
||||
ret.VisorToggled = row.Visor;
|
||||
}
|
||||
|
||||
list.Add(ret);
|
||||
}
|
||||
|
||||
foreach (var baseRow in bnpcSheet)
|
||||
{
|
||||
if (baseRow.ModelChara.Value!.Type != 1)
|
||||
continue;
|
||||
|
||||
var bnpcNameIds = identifier.GetBnpcNames(baseRow.RowId);
|
||||
if (bnpcNameIds.Count == 0)
|
||||
continue;
|
||||
|
||||
var (valid, customize) = FromBnpcCustomize(baseRow.BNpcCustomize.Value!);
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
var equip = baseRow.NpcEquip.Value!;
|
||||
var ret = new NpcData
|
||||
{
|
||||
Customize = customize,
|
||||
Id = baseRow.RowId,
|
||||
Kind = ObjectKind.BattleNpc,
|
||||
};
|
||||
ApplyNpcEquip(ref ret, equip);
|
||||
foreach (var bnpcNameId in bnpcNameIds)
|
||||
{
|
||||
if (bnpcNames.TryGetValue(bnpcNameId.Id, out var name) && !name.IsNullOrWhitespace())
|
||||
list.Add(ret with { Name = name });
|
||||
}
|
||||
}
|
||||
|
||||
var groups = list.GroupBy(d => d.Name).ToDictionary(g => g.Key, g => g.ToList());
|
||||
list.Clear();
|
||||
foreach (var (name, duplicates) in groups.OrderBy(kvp => kvp.Key))
|
||||
{
|
||||
for (var i = 0; i < duplicates.Count; ++i)
|
||||
{
|
||||
var current = duplicates[i];
|
||||
var add = true;
|
||||
for (var j = 0; j < i; ++j)
|
||||
{
|
||||
if (current.DataEquals(duplicates[j]))
|
||||
{
|
||||
duplicates.RemoveAt(i--);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicates.Count == 1)
|
||||
list.Add(duplicates[0]);
|
||||
else
|
||||
list.AddRange(duplicates
|
||||
.Select(duplicate => duplicate with { Name = $"{name} ({(duplicate.Kind is ObjectKind.BattleNpc ? 'B' : 'E')}{duplicate.Id})" }));
|
||||
}
|
||||
|
||||
var lastWeird = list.FindIndex(d => char.IsAsciiLetterOrDigit(d.Name[0]));
|
||||
if (lastWeird != -1)
|
||||
{
|
||||
list.AddRange(list.Take(lastWeird));
|
||||
list.RemoveRange(0, lastWeird);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
public static Dictionary<(SubRace, Gender), IReadOnlyList<(CustomizeIndex, CustomizeValue)>> CreateNpcData(CustomizationSet[] sets,
|
||||
ExcelSheet<BNpcCustomize> bNpc, ExcelSheet<ENpcBase> eNpc)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Reflection;
|
||||
using Dalamud.Plugin;
|
||||
using Glamourer.Api;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
|
|
@ -32,11 +33,13 @@ public class Glamourer : IDalamudPlugin
|
|||
{
|
||||
_services = ServiceManager.CreateProvider(pluginInterface, Log);
|
||||
Messager = _services.GetRequiredService<MessageService>();
|
||||
_services.GetRequiredService<VisorService>();
|
||||
_services.GetRequiredService<WeaponService>();
|
||||
_services.GetRequiredService<ScalingService>();
|
||||
_services.GetRequiredService<StateListener>(); // Initialize State Listener.
|
||||
_services.GetRequiredService<GlamourerWindowSystem>(); // initialize ui.
|
||||
_services.GetRequiredService<CommandService>(); // initialize commands.
|
||||
_services.GetRequiredService<VisorService>();
|
||||
_services.GetRequiredService<ScalingService>();
|
||||
_services.GetRequiredService<GlamourerIpc>(); // initialize IPC.
|
||||
Log.Information($"Glamourer v{Version} loaded successfully.");
|
||||
}
|
||||
catch
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
113
Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs
Normal file
113
Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectManager) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> $"Active Actors ({_stateManager.Count})###Active Actors";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
_objectManager.Update();
|
||||
foreach (var (identifier, actors) in _objectManager)
|
||||
{
|
||||
if (ImGuiUtil.DrawDisabledButton($"{FontAwesomeIcon.Trash.ToIconString()}##{actors.Label}", new Vector2(ImGui.GetFrameHeight()),
|
||||
string.Empty, !_stateManager.ContainsKey(identifier), true))
|
||||
_stateManager.DeleteState(identifier);
|
||||
|
||||
ImGui.SameLine();
|
||||
using var t = ImRaii.TreeNode(actors.Label);
|
||||
if (!t)
|
||||
continue;
|
||||
|
||||
if (_stateManager.GetOrCreate(identifier, actors.Objects[0], out var state))
|
||||
DrawState(_stateManager, actors, state);
|
||||
else
|
||||
ImGui.TextUnformatted("Invalid actor.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawState(StateManager stateManager, ActorData data, ActorState state)
|
||||
{
|
||||
using var table = ImRaii.Table("##state", 7, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Name");
|
||||
ImGuiUtil.DrawTableColumn(state.Identifier.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Reset"))
|
||||
stateManager.ResetState(state, StateChanged.Source.Manual);
|
||||
|
||||
ImGui.TableNextRow();
|
||||
|
||||
static void PrintRow<T>(string label, T actor, T model, StateChanged.Source source) where T : notnull
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(label);
|
||||
ImGuiUtil.DrawTableColumn(actor.ToString()!);
|
||||
ImGuiUtil.DrawTableColumn(model.ToString()!);
|
||||
ImGuiUtil.DrawTableColumn(source.ToString());
|
||||
}
|
||||
|
||||
static string ItemString(in DesignData data, EquipSlot slot)
|
||||
{
|
||||
var item = data.Item(slot);
|
||||
return $"{item.Name} ({item.ModelId.Id}{(item.WeaponType != 0 ? $"-{item.WeaponType.Id}" : string.Empty)}-{item.Variant})";
|
||||
}
|
||||
|
||||
PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state[ActorState.MetaIndex.ModelId]);
|
||||
ImGui.TableNextRow();
|
||||
PrintRow("Wetness", state.BaseData.IsWet(), state.ModelData.IsWet(), state[ActorState.MetaIndex.Wetness]);
|
||||
ImGui.TableNextRow();
|
||||
|
||||
if (state.BaseData.IsHuman && state.ModelData.IsHuman)
|
||||
{
|
||||
PrintRow("Hat Visible", state.BaseData.IsHatVisible(), state.ModelData.IsHatVisible(), state[ActorState.MetaIndex.HatState]);
|
||||
ImGui.TableNextRow();
|
||||
PrintRow("Visor Toggled", state.BaseData.IsVisorToggled(), state.ModelData.IsVisorToggled(),
|
||||
state[ActorState.MetaIndex.VisorState]);
|
||||
ImGui.TableNextRow();
|
||||
PrintRow("Weapon Visible", state.BaseData.IsWeaponVisible(), state.ModelData.IsWeaponVisible(),
|
||||
state[ActorState.MetaIndex.WeaponState]);
|
||||
ImGui.TableNextRow();
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
|
||||
{
|
||||
PrintRow(slot.ToName(), ItemString(state.BaseData, slot), ItemString(state.ModelData, slot), state[slot, false]);
|
||||
ImGuiUtil.DrawTableColumn(state.BaseData.Stain(slot).Id.ToString());
|
||||
ImGuiUtil.DrawTableColumn(state.ModelData.Stain(slot).Id.ToString());
|
||||
ImGuiUtil.DrawTableColumn(state[slot, true].ToString());
|
||||
}
|
||||
|
||||
foreach (var type in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
PrintRow(type.ToDefaultName(), state.BaseData.Customize[type].Value, state.ModelData.Customize[type].Value, state[type]);
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(string.Join(" ", state.BaseData.GetCustomizeBytes().Select(b => b.ToString("X2"))));
|
||||
ImGuiUtil.DrawTableColumn(string.Join(" ", state.ModelData.GetCustomizeBytes().Select(b => b.ToString("X2"))));
|
||||
ImGui.TableNextRow();
|
||||
ImGuiUtil.DrawTableColumn(string.Join(" ", state.BaseData.GetEquipmentBytes().Select(b => b.ToString("X2"))));
|
||||
ImGuiUtil.DrawTableColumn(string.Join(" ", state.ModelData.GetEquipmentBytes().Select(b => b.ToString("X2"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Glamourer/Gui/Tabs/DebugTab/ActorServicePanel.cs
Normal file
73
Glamourer/Gui/Tabs/DebugTab/ActorServicePanel.cs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class ActorServicePanel(ActorService _actors, ItemManager _items) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Actor Service";
|
||||
|
||||
public bool Disabled
|
||||
=> !_actors.Valid;
|
||||
|
||||
private string _bnpcFilter = string.Empty;
|
||||
private string _enpcFilter = string.Empty;
|
||||
private string _companionFilter = string.Empty;
|
||||
private string _mountFilter = string.Empty;
|
||||
private string _ornamentFilter = string.Empty;
|
||||
private string _worldFilter = string.Empty;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
DrawBnpcTable();
|
||||
DebugTab.DrawNameTable("ENPCs", ref _enpcFilter, _actors.AwaitedService.Data.ENpcs.Select(kvp => (kvp.Key, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Companions", ref _companionFilter, _actors.AwaitedService.Data.Companions.Select(kvp => (kvp.Key, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Mounts", ref _mountFilter, _actors.AwaitedService.Data.Mounts.Select(kvp => (kvp.Key, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Ornaments", ref _ornamentFilter, _actors.AwaitedService.Data.Ornaments.Select(kvp => (kvp.Key, kvp.Value)));
|
||||
DebugTab.DrawNameTable("Worlds", ref _worldFilter, _actors.AwaitedService.Data.Worlds.Select(kvp => ((uint)kvp.Key, kvp.Value)));
|
||||
}
|
||||
|
||||
private void DrawBnpcTable()
|
||||
{
|
||||
using var _ = ImRaii.PushId(1);
|
||||
using var tree = ImRaii.TreeNode("BNPCs");
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
var resetScroll = ImGui.InputTextWithHint("##filter", "Filter...", ref _bnpcFilter, 256);
|
||||
var height = ImGui.GetTextLineHeightWithSpacing() + 2 * ImGui.GetStyle().CellPadding.Y;
|
||||
using var table = ImRaii.Table("##table", 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.BordersOuter,
|
||||
new Vector2(-1, 10 * height));
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
if (resetScroll)
|
||||
ImGui.SetScrollY(0);
|
||||
ImGui.TableSetupColumn("1", ImGuiTableColumnFlags.WidthFixed, 50 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("2", ImGuiTableColumnFlags.WidthStretch);
|
||||
ImGui.TableSetupColumn("3", ImGuiTableColumnFlags.WidthStretch);
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(height);
|
||||
ImGui.TableNextRow();
|
||||
var data = _actors.AwaitedService.Data.BNpcs.Select(kvp => (kvp.Key, kvp.Key.ToString("D5"), kvp.Value));
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(data, skips,
|
||||
p => p.Item2.Contains(_bnpcFilter) || p.Item3.Contains(_bnpcFilter, StringComparison.OrdinalIgnoreCase),
|
||||
p =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(p.Item2);
|
||||
ImGuiUtil.DrawTableColumn(p.Item3);
|
||||
var bnpcs = _items.IdentifierService.AwaitedService.GetBnpcsFromName(p.Item1);
|
||||
ImGuiUtil.DrawTableColumn(string.Join(", ", bnpcs.Select(b => b.Id.ToString())));
|
||||
});
|
||||
ImGuiClip.DrawEndDummy(remainder, height);
|
||||
}
|
||||
}
|
||||
48
Glamourer/Gui/Tabs/DebugTab/AutoDesignPanel.cs
Normal file
48
Glamourer/Gui/Tabs/DebugTab/AutoDesignPanel.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
using Glamourer.Automation;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class AutoDesignPanel(AutoDesignManager _autoDesignManager) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Auto Designs";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
foreach (var (set, idx) in _autoDesignManager.WithIndex())
|
||||
{
|
||||
using var id = ImRaii.PushId(idx);
|
||||
using var tree = ImRaii.TreeNode(set.Name);
|
||||
if (!tree)
|
||||
continue;
|
||||
|
||||
using var table = ImRaii.Table("##autoDesign", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
continue;
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Name");
|
||||
ImGuiUtil.DrawTableColumn(set.Name);
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Index");
|
||||
ImGuiUtil.DrawTableColumn(idx.ToString());
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Enabled");
|
||||
ImGuiUtil.DrawTableColumn(set.Enabled.ToString());
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Actor");
|
||||
ImGuiUtil.DrawTableColumn(set.Identifiers[0].ToString());
|
||||
|
||||
foreach (var (design, designIdx) in set.Designs.WithIndex())
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn($"{design.Name(false)} ({designIdx})");
|
||||
ImGuiUtil.DrawTableColumn($"{design.ApplicationType} {design.Jobs.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Glamourer/Gui/Tabs/DebugTab/CustomizationServicePanel.cs
Normal file
67
Glamourer/Gui/Tabs/DebugTab/CustomizationServicePanel.cs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class CustomizationServicePanel(CustomizationService _customization) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Customization Service";
|
||||
|
||||
public bool Disabled
|
||||
=> !_customization.Valid;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
foreach (var clan in _customization.AwaitedService.Clans)
|
||||
{
|
||||
foreach (var gender in _customization.AwaitedService.Genders)
|
||||
{
|
||||
var set = _customization.AwaitedService.GetList(clan, gender);
|
||||
DrawCustomizationInfo(set);
|
||||
DrawNpcCustomizationInfo(set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCustomizationInfo(CustomizationSet set)
|
||||
{
|
||||
using var tree = ImRaii.TreeNode($"{_customization.ClanName(set.Clan, set.Gender)} {set.Gender}");
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
using var table = ImRaii.Table("data", 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(index.ToString());
|
||||
ImGuiUtil.DrawTableColumn(set.Option(index));
|
||||
ImGuiUtil.DrawTableColumn(set.IsAvailable(index) ? "Available" : "Unavailable");
|
||||
ImGuiUtil.DrawTableColumn(set.Type(index).ToString());
|
||||
ImGuiUtil.DrawTableColumn(set.Count(index).ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawNpcCustomizationInfo(CustomizationSet set)
|
||||
{
|
||||
using var tree = ImRaii.TreeNode($"{_customization.ClanName(set.Clan, set.Gender)} {set.Gender} (NPC Options)");
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
using var table = ImRaii.Table("npc", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
foreach (var (index, value) in set.NpcOptions)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(index.ToString());
|
||||
ImGuiUtil.DrawTableColumn(value.Value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Glamourer/Gui/Tabs/DebugTab/CustomizationUnlockPanel.cs
Normal file
45
Glamourer/Gui/Tabs/DebugTab/CustomizationUnlockPanel.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class CustomizationUnlockPanel(CustomizeUnlockManager _customizeUnlocks) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Customizations";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var table = ImRaii.Table("customizationUnlocks", 6,
|
||||
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.BordersOuter,
|
||||
new Vector2(ImGui.GetContentRegionAvail().X, 12 * ImGui.GetTextLineHeight()));
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
||||
ImGui.TableNextRow();
|
||||
var remainder = ImGuiClip.ClippedDraw(_customizeUnlocks.Unlockable, skips, t =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(t.Key.Index.ToDefaultName());
|
||||
ImGuiUtil.DrawTableColumn(t.Key.CustomizeId.ToString());
|
||||
ImGuiUtil.DrawTableColumn(t.Key.Value.Value.ToString());
|
||||
ImGuiUtil.DrawTableColumn(t.Value.Data.ToString());
|
||||
ImGuiUtil.DrawTableColumn(t.Value.Name);
|
||||
ImGuiUtil.DrawTableColumn(_customizeUnlocks.IsUnlocked(t.Key, out var time)
|
||||
? time == DateTimeOffset.MinValue
|
||||
? "Always"
|
||||
: time.LocalDateTime.ToString("g")
|
||||
: "Never");
|
||||
}, _customizeUnlocks.Unlockable.Count);
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
|
||||
}
|
||||
}
|
||||
42
Glamourer/Gui/Tabs/DebugTab/DatFilePanel.cs
Normal file
42
Glamourer/Gui/Tabs/DebugTab/DatFilePanel.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using System.IO;
|
||||
using System.Numerics;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Interop;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class DatFilePanel(ImportService _importService) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Character Dat File";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private string _datFilePath = string.Empty;
|
||||
private DatCharacterFile? _datFile = null;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
ImGui.InputTextWithHint("##datFilePath", "Dat File Path...", ref _datFilePath, 256);
|
||||
var exists = _datFilePath.Length > 0 && File.Exists(_datFilePath);
|
||||
if (ImGuiUtil.DrawDisabledButton("Load##Dat", Vector2.Zero, string.Empty, !exists))
|
||||
_datFile = _importService.LoadDat(_datFilePath, out var tmp) ? tmp : null;
|
||||
|
||||
if (ImGuiUtil.DrawDisabledButton("Save##Dat", Vector2.Zero, string.Empty, _datFilePath.Length == 0 || _datFile == null))
|
||||
_importService.SaveDesignAsDat(_datFilePath, _datFile!.Value.Customize, _datFile!.Value.Description);
|
||||
|
||||
if (_datFile != null)
|
||||
{
|
||||
ImGui.TextUnformatted(_datFile.Value.Magic.ToString());
|
||||
ImGui.TextUnformatted(_datFile.Value.Version.ToString());
|
||||
ImGui.TextUnformatted(_datFile.Value.Time.LocalDateTime.ToString("g"));
|
||||
ImGui.TextUnformatted(_datFile.Value.Voice.ToString());
|
||||
ImGui.TextUnformatted(_datFile.Value.Customize.Data.ToString());
|
||||
ImGui.TextUnformatted(_datFile.Value.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Glamourer/Gui/Tabs/DebugTab/DebugTab.cs
Normal file
91
Glamourer/Gui/Tabs/DebugTab/DebugTab.cs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.Utility;
|
||||
using ImGuiNET;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using ImGuiClip = Dalamud.Interface.Utility.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public unsafe class DebugTab(IServiceProvider _provider) : ITab
|
||||
{
|
||||
private readonly Configuration _config = _provider.GetRequiredService<Configuration>();
|
||||
|
||||
public bool IsVisible
|
||||
=> _config.DebugMode;
|
||||
|
||||
public ReadOnlySpan<byte> Label
|
||||
=> "Debug"u8;
|
||||
|
||||
private readonly DebugTabHeader[] _headers =
|
||||
[
|
||||
DebugTabHeader.CreateInterop(_provider),
|
||||
DebugTabHeader.CreateGameData(_provider),
|
||||
DebugTabHeader.CreateDesigns(_provider),
|
||||
DebugTabHeader.CreateState(_provider),
|
||||
DebugTabHeader.CreateUnlocks(_provider),
|
||||
];
|
||||
|
||||
public void DrawContent()
|
||||
{
|
||||
using var child = ImRaii.Child("MainWindowChild");
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
foreach (var header in _headers)
|
||||
header.Draw();
|
||||
}
|
||||
|
||||
public static void DrawInputModelSet(bool withWeapon, ref int setId, ref int secondaryId, ref int variant)
|
||||
{
|
||||
ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.InputInt("##SetId", ref setId, 0, 0);
|
||||
if (withWeapon)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.InputInt("##TypeId", ref secondaryId, 0, 0);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.InputInt("##Variant", ref variant, 0, 0);
|
||||
}
|
||||
|
||||
public static void DrawNameTable(string label, ref string filter, IEnumerable<(uint, string)> names)
|
||||
{
|
||||
using var _ = ImRaii.PushId(label);
|
||||
using var tree = ImRaii.TreeNode(label);
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
var resetScroll = ImGui.InputTextWithHint("##filter", "Filter...", ref filter, 256);
|
||||
var height = ImGui.GetTextLineHeightWithSpacing() + 2 * ImGui.GetStyle().CellPadding.Y;
|
||||
using var table = ImRaii.Table("##table", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.BordersOuter,
|
||||
new Vector2(-1, 10 * height));
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
if (resetScroll)
|
||||
ImGui.SetScrollY(0);
|
||||
ImGui.TableSetupColumn("1", ImGuiTableColumnFlags.WidthFixed, 50 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("2", ImGuiTableColumnFlags.WidthStretch);
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(height);
|
||||
ImGui.TableNextColumn();
|
||||
var f = filter;
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(names.Select(p => (p.Item1.ToString("D5"), p.Item2)), skips,
|
||||
p => p.Item1.Contains(f) || p.Item2.Contains(f, StringComparison.OrdinalIgnoreCase),
|
||||
p =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(p.Item1);
|
||||
ImGuiUtil.DrawTableColumn(p.Item2);
|
||||
});
|
||||
ImGuiClip.DrawEndDummy(remainder, height);
|
||||
}
|
||||
}
|
||||
93
Glamourer/Gui/Tabs/DebugTab/DebugTabHeader.cs
Normal file
93
Glamourer/Gui/Tabs/DebugTab/DebugTabHeader.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ImGuiNET;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public interface IDebugTabTree
|
||||
{
|
||||
public string Label { get; }
|
||||
public void Draw();
|
||||
|
||||
public bool Disabled { get; }
|
||||
}
|
||||
|
||||
public class DebugTabHeader(string label, params IDebugTabTree[] subTrees)
|
||||
{
|
||||
public string Label { get; } = label;
|
||||
public IReadOnlyList<IDebugTabTree> SubTrees { get; } = subTrees;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (!ImGui.CollapsingHeader(Label))
|
||||
return;
|
||||
|
||||
foreach (var subTree in SubTrees)
|
||||
{
|
||||
using (var disabled = ImRaii.Disabled(subTree.Disabled))
|
||||
{
|
||||
using var tree = ImRaii.TreeNode(subTree.Label);
|
||||
if (!tree)
|
||||
continue;
|
||||
}
|
||||
|
||||
subTree.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
public static DebugTabHeader CreateInterop(IServiceProvider provider)
|
||||
=> new
|
||||
(
|
||||
"Interop",
|
||||
provider.GetRequiredService<ModelEvaluationPanel>(),
|
||||
provider.GetRequiredService<ObjectManagerPanel>(),
|
||||
provider.GetRequiredService<PenumbraPanel>(),
|
||||
provider.GetRequiredService<IpcTesterPanel>(),
|
||||
provider.GetRequiredService<DatFilePanel>()
|
||||
);
|
||||
|
||||
public static DebugTabHeader CreateGameData(IServiceProvider provider)
|
||||
=> new
|
||||
(
|
||||
"Game Data",
|
||||
provider.GetRequiredService<IdentifierPanel>(),
|
||||
provider.GetRequiredService<RestrictedGearPanel>(),
|
||||
provider.GetRequiredService<ActorServicePanel>(),
|
||||
provider.GetRequiredService<ItemManagerPanel>(),
|
||||
provider.GetRequiredService<StainPanel>(),
|
||||
provider.GetRequiredService<CustomizationServicePanel>(),
|
||||
provider.GetRequiredService<JobPanel>(),
|
||||
provider.GetRequiredService<NpcAppearancePanel>()
|
||||
);
|
||||
|
||||
public static DebugTabHeader CreateDesigns(IServiceProvider provider)
|
||||
=> new
|
||||
(
|
||||
"Designs",
|
||||
provider.GetRequiredService<DesignManagerPanel>(),
|
||||
provider.GetRequiredService<DesignConverterPanel>(),
|
||||
provider.GetRequiredService<DesignTesterPanel>(),
|
||||
provider.GetRequiredService<AutoDesignPanel>()
|
||||
);
|
||||
|
||||
public static DebugTabHeader CreateState(IServiceProvider provider)
|
||||
=> new
|
||||
(
|
||||
"State",
|
||||
provider.GetRequiredService<ActiveStatePanel>(),
|
||||
provider.GetRequiredService<RetainedStatePanel>(),
|
||||
provider.GetRequiredService<FunPanel>()
|
||||
);
|
||||
|
||||
public static DebugTabHeader CreateUnlocks(IServiceProvider provider)
|
||||
=> new
|
||||
(
|
||||
"Unlocks",
|
||||
provider.GetRequiredService<CustomizationUnlockPanel>(),
|
||||
provider.GetRequiredService<ItemUnlockPanel>(),
|
||||
provider.GetRequiredService<UnlockableItemsPanel>(),
|
||||
provider.GetRequiredService<InventoryPanel>()
|
||||
);
|
||||
}
|
||||
97
Glamourer/Gui/Tabs/DebugTab/DesignConverterPanel.cs
Normal file
97
Glamourer/Gui/Tabs/DebugTab/DesignConverterPanel.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Utility;
|
||||
using ImGuiNET;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class DesignConverterPanel(DesignConverter _designConverter) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Design Converter";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private string _clipboardText = string.Empty;
|
||||
private byte[] _clipboardData = [];
|
||||
private byte[] _dataUncompressed = [];
|
||||
private byte _version = 0;
|
||||
private string _textUncompressed = string.Empty;
|
||||
private JObject? _json = null;
|
||||
private DesignBase? _tmpDesign = null;
|
||||
private Exception? _clipboardProblem = null;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (ImGui.Button("Import Clipboard"))
|
||||
{
|
||||
_clipboardText = string.Empty;
|
||||
_clipboardData = [];
|
||||
_dataUncompressed = [];
|
||||
_textUncompressed = string.Empty;
|
||||
_json = null;
|
||||
_tmpDesign = null;
|
||||
_clipboardProblem = null;
|
||||
|
||||
try
|
||||
{
|
||||
_clipboardText = ImGui.GetClipboardText();
|
||||
_clipboardData = Convert.FromBase64String(_clipboardText);
|
||||
_version = _clipboardData[0];
|
||||
if (_version == 5)
|
||||
_clipboardData = _clipboardData[DesignBase64Migration.Base64SizeV4..];
|
||||
_version = _clipboardData.Decompress(out _dataUncompressed);
|
||||
_textUncompressed = Encoding.UTF8.GetString(_dataUncompressed);
|
||||
_json = JObject.Parse(_textUncompressed);
|
||||
_tmpDesign = _designConverter.FromBase64(_clipboardText, true, true, out _);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_clipboardProblem = ex;
|
||||
}
|
||||
}
|
||||
|
||||
if (_clipboardText.Length > 0)
|
||||
{
|
||||
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGuiUtil.TextWrapped(_clipboardText);
|
||||
}
|
||||
|
||||
if (_clipboardData.Length > 0)
|
||||
{
|
||||
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGuiUtil.TextWrapped(string.Join(" ", _clipboardData.Select(b => b.ToString("X2"))));
|
||||
}
|
||||
|
||||
if (_dataUncompressed.Length > 0)
|
||||
{
|
||||
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGuiUtil.TextWrapped(string.Join(" ", _dataUncompressed.Select(b => b.ToString("X2"))));
|
||||
}
|
||||
|
||||
if (_textUncompressed.Length > 0)
|
||||
{
|
||||
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGuiUtil.TextWrapped(_textUncompressed);
|
||||
}
|
||||
|
||||
if (_json != null)
|
||||
ImGui.TextUnformatted("JSON Parsing Successful!");
|
||||
|
||||
if (_tmpDesign != null)
|
||||
DesignManagerPanel.DrawDesign(_tmpDesign, null);
|
||||
|
||||
if (_clipboardProblem != null)
|
||||
{
|
||||
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGuiUtil.TextWrapped(_clipboardProblem.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
122
Glamourer/Gui/Tabs/DebugTab/DesignManagerPanel.cs
Normal file
122
Glamourer/Gui/Tabs/DebugTab/DesignManagerPanel.cs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _designFileSystem) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> $"Design Manager ({_designManager.Designs.Count} Designs)###Design Manager";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
foreach (var (design, idx) in _designManager.Designs.WithIndex())
|
||||
{
|
||||
using var t = ImRaii.TreeNode($"{design.Name}##{idx}");
|
||||
if (!t)
|
||||
continue;
|
||||
|
||||
DrawDesign(design, _designFileSystem);
|
||||
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomizeRaw,
|
||||
design.DoApplyHatVisible(),
|
||||
design.DoApplyVisorToggle(), design.DoApplyWeaponVisible(), design.WriteProtected());
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGuiUtil.TextWrapped(base64);
|
||||
if (ImGui.IsItemClicked())
|
||||
ImGui.SetClipboardText(base64);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawDesign(DesignBase design, DesignFileSystem? fileSystem)
|
||||
{
|
||||
using var table = ImRaii.Table("##equip", 8, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
|
||||
if (design is Design d)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn("Name");
|
||||
ImGuiUtil.DrawTableColumn(d.Name);
|
||||
ImGuiUtil.DrawTableColumn($"({d.Index})");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted("Description (Hover)");
|
||||
ImGuiUtil.HoverTooltip(d.Description);
|
||||
ImGui.TableNextRow();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Identifier");
|
||||
ImGuiUtil.DrawTableColumn(d.Identifier.ToString());
|
||||
ImGui.TableNextRow();
|
||||
ImGuiUtil.DrawTableColumn("Design File System Path");
|
||||
if (fileSystem != null)
|
||||
ImGuiUtil.DrawTableColumn(fileSystem.FindLeaf(d, out var leaf) ? leaf.FullName() : "No Path Known");
|
||||
ImGui.TableNextRow();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Creation");
|
||||
ImGuiUtil.DrawTableColumn(d.CreationDate.ToString());
|
||||
ImGui.TableNextRow();
|
||||
ImGuiUtil.DrawTableColumn("Update");
|
||||
ImGuiUtil.DrawTableColumn(d.LastEdit.ToString());
|
||||
ImGui.TableNextRow();
|
||||
ImGuiUtil.DrawTableColumn("Tags");
|
||||
ImGuiUtil.DrawTableColumn(string.Join(", ", d.Tags));
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
|
||||
{
|
||||
var item = design.DesignData.Item(slot);
|
||||
var apply = design.DoApplyEquip(slot);
|
||||
var stain = design.DesignData.Stain(slot);
|
||||
var applyStain = design.DoApplyStain(slot);
|
||||
var crest = design.DesignData.Crest(slot.ToCrestFlag());
|
||||
var applyCrest = design.DoApplyCrest(slot.ToCrestFlag());
|
||||
ImGuiUtil.DrawTableColumn(slot.ToName());
|
||||
ImGuiUtil.DrawTableColumn(item.Name);
|
||||
ImGuiUtil.DrawTableColumn(item.ItemId.ToString());
|
||||
ImGuiUtil.DrawTableColumn(apply ? "Apply" : "Keep");
|
||||
ImGuiUtil.DrawTableColumn(stain.ToString());
|
||||
ImGuiUtil.DrawTableColumn(applyStain ? "Apply" : "Keep");
|
||||
ImGuiUtil.DrawTableColumn(crest.ToString());
|
||||
ImGuiUtil.DrawTableColumn(applyCrest ? "Apply" : "Keep");
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Hat Visible");
|
||||
ImGuiUtil.DrawTableColumn(design.DesignData.IsHatVisible().ToString());
|
||||
ImGuiUtil.DrawTableColumn(design.DoApplyHatVisible() ? "Apply" : "Keep");
|
||||
ImGui.TableNextRow();
|
||||
ImGuiUtil.DrawTableColumn("Visor Toggled");
|
||||
ImGuiUtil.DrawTableColumn(design.DesignData.IsVisorToggled().ToString());
|
||||
ImGuiUtil.DrawTableColumn(design.DoApplyVisorToggle() ? "Apply" : "Keep");
|
||||
ImGui.TableNextRow();
|
||||
ImGuiUtil.DrawTableColumn("Weapon Visible");
|
||||
ImGuiUtil.DrawTableColumn(design.DesignData.IsWeaponVisible().ToString());
|
||||
ImGuiUtil.DrawTableColumn(design.DoApplyWeaponVisible() ? "Apply" : "Keep");
|
||||
ImGui.TableNextRow();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Model ID");
|
||||
ImGuiUtil.DrawTableColumn(design.DesignData.ModelId.ToString());
|
||||
ImGui.TableNextRow();
|
||||
|
||||
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
var value = design.DesignData.Customize[index];
|
||||
var apply = design.DoApplyCustomize(index);
|
||||
ImGuiUtil.DrawTableColumn(index.ToDefaultName());
|
||||
ImGuiUtil.DrawTableColumn(value.Value.ToString());
|
||||
ImGuiUtil.DrawTableColumn(apply ? "Apply" : "Keep");
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Is Wet");
|
||||
ImGuiUtil.DrawTableColumn(design.DesignData.IsWet().ToString());
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
}
|
||||
202
Glamourer/Gui/Tabs/DebugTab/DesignTesterPanel.cs
Normal file
202
Glamourer/Gui/Tabs/DebugTab/DesignTesterPanel.cs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class DesignTesterPanel(ItemManager _items, HumanModelList _humans) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Base64 Design Tester";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private string _base64 = string.Empty;
|
||||
private string _restore = string.Empty;
|
||||
private byte[] _base64Bytes = [];
|
||||
private byte[] _restoreBytes = [];
|
||||
private DesignData _parse64 = new();
|
||||
private Exception? _parse64Failure;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
DrawBase64Input();
|
||||
DrawDesignData();
|
||||
DrawBytes();
|
||||
}
|
||||
|
||||
private void DrawBase64Input()
|
||||
{
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
ImGui.InputTextWithHint("##base64", "Base 64 input...", ref _base64, 2047);
|
||||
if (!ImGui.IsItemDeactivatedAfterEdit())
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_base64Bytes = Convert.FromBase64String(_base64);
|
||||
_parse64Failure = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_base64Bytes = Array.Empty<byte>();
|
||||
_parse64Failure = ex;
|
||||
}
|
||||
|
||||
if (_parse64Failure != null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_parse64 = DesignBase64Migration.MigrateBase64(_items, _humans, _base64, out var ef, out var cf, out var wp, out var ah,
|
||||
out var av,
|
||||
out var aw);
|
||||
_restore = DesignBase64Migration.CreateOldBase64(in _parse64, ef, cf, ah, av, aw, wp);
|
||||
_restoreBytes = Convert.FromBase64String(_restore);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_parse64Failure = ex;
|
||||
_restore = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawDesignData()
|
||||
{
|
||||
if (_parse64Failure != null)
|
||||
{
|
||||
ImGuiUtil.TextWrapped(_parse64Failure.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (_restore.Length <= 0)
|
||||
return;
|
||||
|
||||
DrawDesignData(_parse64);
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TextUnformatted(_base64);
|
||||
using (var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = 0 }))
|
||||
{
|
||||
foreach (var (c1, c2) in _restore.Zip(_base64))
|
||||
{
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Text, 0xFF4040D0, c1 != c2);
|
||||
ImGui.TextUnformatted(c1.ToString());
|
||||
ImGui.SameLine();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
|
||||
foreach (var ((b1, b2), idx) in _base64Bytes.Zip(_restoreBytes).WithIndex())
|
||||
{
|
||||
using (var group = ImRaii.Group())
|
||||
{
|
||||
ImGui.TextUnformatted(idx.ToString("D2"));
|
||||
ImGui.TextUnformatted(b1.ToString("X2"));
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Text, 0xFF4040D0, b1 != b2);
|
||||
ImGui.TextUnformatted(b2.ToString("X2"));
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
}
|
||||
|
||||
private void DrawBytes()
|
||||
{
|
||||
if (_parse64Failure == null || _base64Bytes.Length <= 0)
|
||||
return;
|
||||
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
foreach (var (b, idx) in _base64Bytes.WithIndex())
|
||||
{
|
||||
using (var group = ImRaii.Group())
|
||||
{
|
||||
ImGui.TextUnformatted(idx.ToString("D2"));
|
||||
ImGui.TextUnformatted(b.ToString("X2"));
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
}
|
||||
|
||||
public static void DrawDesignData(in DesignData data)
|
||||
{
|
||||
if (data.IsHuman)
|
||||
DrawHumanData(data);
|
||||
else
|
||||
DrawMonsterData(data);
|
||||
}
|
||||
|
||||
private static void DrawHumanData(in DesignData data)
|
||||
{
|
||||
using var table = ImRaii.Table("##equip", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
|
||||
{
|
||||
var item = data.Item(slot);
|
||||
var stain = data.Stain(slot);
|
||||
var crest = data.Crest(slot.ToCrestFlag());
|
||||
ImGuiUtil.DrawTableColumn(slot.ToName());
|
||||
ImGuiUtil.DrawTableColumn(item.Name);
|
||||
ImGuiUtil.DrawTableColumn(item.ItemId.ToString());
|
||||
ImGuiUtil.DrawTableColumn(stain.ToString());
|
||||
ImGuiUtil.DrawTableColumn(crest.ToString());
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Hat Visible");
|
||||
ImGuiUtil.DrawTableColumn(data.IsHatVisible().ToString());
|
||||
ImGui.TableNextRow();
|
||||
ImGuiUtil.DrawTableColumn("Visor Toggled");
|
||||
ImGuiUtil.DrawTableColumn(data.IsVisorToggled().ToString());
|
||||
ImGui.TableNextRow();
|
||||
ImGuiUtil.DrawTableColumn("Weapon Visible");
|
||||
ImGuiUtil.DrawTableColumn(data.IsWeaponVisible().ToString());
|
||||
ImGui.TableNextRow();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Model ID");
|
||||
ImGuiUtil.DrawTableColumn(data.ModelId.ToString());
|
||||
ImGui.TableNextRow();
|
||||
|
||||
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
var value = data.Customize[index];
|
||||
ImGuiUtil.DrawTableColumn(index.ToDefaultName());
|
||||
ImGuiUtil.DrawTableColumn(value.Value.ToString());
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Is Wet");
|
||||
ImGuiUtil.DrawTableColumn(data.IsWet().ToString());
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
|
||||
private static void DrawMonsterData(in DesignData data)
|
||||
{
|
||||
ImGui.TextUnformatted($"Model ID {data.ModelId}");
|
||||
ImGui.Separator();
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TextUnformatted("Customize Array");
|
||||
ImGui.Separator();
|
||||
ImGuiUtil.TextWrapped(string.Join(" ", data.GetCustomizeBytes().Select(b => b.ToString("X2"))));
|
||||
|
||||
ImGui.TextUnformatted("Equipment Array");
|
||||
ImGui.Separator();
|
||||
ImGuiUtil.TextWrapped(string.Join(" ", data.GetEquipmentBytes().Select(b => b.ToString("X2"))));
|
||||
}
|
||||
}
|
||||
35
Glamourer/Gui/Tabs/DebugTab/FunPanel.cs
Normal file
35
Glamourer/Gui/Tabs/DebugTab/FunPanel.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class FunPanel(FunModule _funModule, Configuration _config) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Fun Module";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
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"))
|
||||
_funModule.ForceFestival(FunModule.FestivalType.Christmas);
|
||||
if (ImGui.Button("Force Halloween"))
|
||||
_funModule.ForceFestival(FunModule.FestivalType.Halloween);
|
||||
if (ImGui.Button("Force April First"))
|
||||
_funModule.ForceFestival(FunModule.FestivalType.AprilFirst);
|
||||
if (ImGui.Button("Force None"))
|
||||
_funModule.ForceFestival(FunModule.FestivalType.None);
|
||||
if (ImGui.Button("Revert"))
|
||||
_funModule.ResetFestival();
|
||||
if (ImGui.Button("Reset Popup"))
|
||||
{
|
||||
_config.DisableFestivals = 1;
|
||||
_config.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
61
Glamourer/Gui/Tabs/DebugTab/IdentifierPanel.cs
Normal file
61
Glamourer/Gui/Tabs/DebugTab/IdentifierPanel.cs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
using System.Linq;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class IdentifierPanel(ItemManager _items) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Identifier Service";
|
||||
|
||||
public bool Disabled
|
||||
=> !_items.IdentifierService.Valid;
|
||||
|
||||
private string _gamePath = string.Empty;
|
||||
private int _setId;
|
||||
private int _secondaryId;
|
||||
private int _variant;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
static void Text(string text)
|
||||
{
|
||||
if (text.Length > 0)
|
||||
ImGui.TextUnformatted(text);
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted("Parse Game Path");
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(300 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.InputTextWithHint("##gamePath", "Enter game path...", ref _gamePath, 256);
|
||||
var fileInfo = _items.IdentifierService.AwaitedService.GamePathParser.GetFileInfo(_gamePath);
|
||||
ImGui.TextUnformatted(
|
||||
$"{fileInfo.ObjectType} {fileInfo.EquipSlot} {fileInfo.PrimaryId} {fileInfo.SecondaryId} {fileInfo.Variant} {fileInfo.BodySlot} {fileInfo.CustomizationType}");
|
||||
Text(string.Join("\n", _items.IdentifierService.AwaitedService.Identify(_gamePath).Keys));
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted("Identify Model");
|
||||
ImGui.SameLine();
|
||||
DebugTab.DrawInputModelSet(true, ref _setId, ref _secondaryId, ref _variant);
|
||||
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var identified = _items.Identify(slot, (SetId)_setId, (Variant)_variant);
|
||||
Text(identified.Name);
|
||||
ImGuiUtil.HoverTooltip(string.Join("\n",
|
||||
_items.IdentifierService.AwaitedService.Identify((SetId)_setId, (Variant)_variant, slot)
|
||||
.Select(i => $"{i.Name} {i.Id} {i.ItemId} {i.IconId}")));
|
||||
}
|
||||
|
||||
var weapon = _items.Identify(EquipSlot.MainHand, (SetId)_setId, (WeaponType)_secondaryId, (Variant)_variant);
|
||||
Text(weapon.Name);
|
||||
ImGuiUtil.HoverTooltip(string.Join("\n",
|
||||
_items.IdentifierService.AwaitedService.Identify((SetId)_setId, (WeaponType)_secondaryId, (Variant)_variant, EquipSlot.MainHand)));
|
||||
}
|
||||
}
|
||||
52
Glamourer/Gui/Tabs/DebugTab/InventoryPanel.cs
Normal file
52
Glamourer/Gui/Tabs/DebugTab/InventoryPanel.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public unsafe class InventoryPanel : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Inventory";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
var inventory = InventoryManager.Instance();
|
||||
if (inventory == null)
|
||||
return;
|
||||
|
||||
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)inventory:X}");
|
||||
|
||||
var equip = inventory->GetInventoryContainer(InventoryType.EquippedItems);
|
||||
if (equip == null || equip->Loaded == 0)
|
||||
return;
|
||||
|
||||
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)equip:X}");
|
||||
|
||||
using var table = ImRaii.Table("items", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < equip->Size; ++i)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(i.ToString());
|
||||
var item = equip->GetInventorySlot(i);
|
||||
if (item == null)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn("NULL");
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(item->ItemID.ToString());
|
||||
ImGuiUtil.DrawTableColumn(item->GlamourID.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)item:X}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
108
Glamourer/Gui/Tabs/DebugTab/IpcTesterPanel.cs
Normal file
108
Glamourer/Gui/Tabs/DebugTab/IpcTesterPanel.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin;
|
||||
using Glamourer.Api;
|
||||
using Glamourer.Interop;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManager _objectManager) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "IPC Tester";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private int _gameObjectIndex;
|
||||
private string _gameObjectName = string.Empty;
|
||||
private string _base64Apply = string.Empty;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
ImGui.InputInt("Game Object Index", ref _gameObjectIndex, 0, 0);
|
||||
ImGui.InputTextWithHint("##gameObject", "Character Name...", ref _gameObjectName, 64);
|
||||
ImGui.InputTextWithHint("##base64", "Design Base64...", ref _base64Apply, 2047);
|
||||
using var table = ImRaii.Table("##ipc", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApiVersions);
|
||||
var (major, minor) = GlamourerIpc.ApiVersionsSubscriber(_pluginInterface).Invoke();
|
||||
ImGuiUtil.DrawTableColumn($"({major}, {minor})");
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetAllCustomization);
|
||||
ImGui.TableNextColumn();
|
||||
var base64 = GlamourerIpc.GetAllCustomizationSubscriber(_pluginInterface).Invoke(_gameObjectName);
|
||||
if (base64 != null)
|
||||
ImGuiUtil.CopyOnClickSelectable(base64);
|
||||
else
|
||||
ImGui.TextUnformatted("Error");
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetAllCustomizationFromCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
base64 = GlamourerIpc.GetAllCustomizationFromCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character);
|
||||
if (base64 != null)
|
||||
ImGuiUtil.CopyOnClickSelectable(base64);
|
||||
else
|
||||
ImGui.TextUnformatted("Error");
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelRevert);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Revert##Name"))
|
||||
GlamourerIpc.RevertSubscriber(_pluginInterface).Invoke(_gameObjectName);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelRevertCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Revert##Character"))
|
||||
GlamourerIpc.RevertCharacterSubscriber(_pluginInterface).Invoke(_objectManager.Objects[_gameObjectIndex] as Character);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAll);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##AllName"))
|
||||
GlamourerIpc.ApplyAllSubscriber(_pluginInterface).Invoke(_base64Apply, _gameObjectName);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAllToCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##AllCharacter"))
|
||||
GlamourerIpc.ApplyAllToCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_base64Apply, _objectManager.Objects[_gameObjectIndex] as Character);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyEquipment);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##EquipName"))
|
||||
GlamourerIpc.ApplyOnlyEquipmentSubscriber(_pluginInterface).Invoke(_base64Apply, _gameObjectName);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyEquipmentToCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##EquipCharacter"))
|
||||
GlamourerIpc.ApplyOnlyEquipmentToCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_base64Apply, _objectManager.Objects[_gameObjectIndex] as Character);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyCustomization);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##CustomizeName"))
|
||||
GlamourerIpc.ApplyOnlyCustomizationSubscriber(_pluginInterface).Invoke(_base64Apply, _gameObjectName);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyCustomizationToCharacter);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Apply##CustomizeCharacter"))
|
||||
GlamourerIpc.ApplyOnlyCustomizationToCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_base64Apply, _objectManager.Objects[_gameObjectIndex] as Character);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelUnlock);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Unlock##CustomizeCharacter"))
|
||||
GlamourerIpc.UnlockSubscriber(_pluginInterface)
|
||||
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character, 1337);
|
||||
|
||||
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelRevertToAutomation);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.Button("Revert##CustomizeCharacter"))
|
||||
GlamourerIpc.RevertToAutomationCharacterSubscriber(_pluginInterface)
|
||||
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character, 1337);
|
||||
}
|
||||
}
|
||||
39
Glamourer/Gui/Tabs/DebugTab/ItemManagerPanel.cs
Normal file
39
Glamourer/Gui/Tabs/DebugTab/ItemManagerPanel.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class ItemManagerPanel(ItemManager _items) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Item Manager";
|
||||
|
||||
public bool Disabled
|
||||
=> !_items.ItemService.Valid;
|
||||
|
||||
private string _itemFilter = string.Empty;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
ImRaii.TreeNode($"Default Sword: {_items.DefaultSword.Name} ({_items.DefaultSword.ItemId}) ({_items.DefaultSword.Weapon()})",
|
||||
ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||
DebugTab.DrawNameTable("All Items (Main)", ref _itemFilter,
|
||||
_items.ItemService.AwaitedService.AllItems(true).Select(p => (p.Item1.Id,
|
||||
$"{p.Item2.Name} ({(p.Item2.WeaponType == 0 ? p.Item2.Armor().ToString() : p.Item2.Weapon().ToString())})"))
|
||||
.OrderBy(p => p.Item1));
|
||||
DebugTab.DrawNameTable("All Items (Off)", ref _itemFilter,
|
||||
_items.ItemService.AwaitedService.AllItems(false).Select(p => (p.Item1.Id,
|
||||
$"{p.Item2.Name} ({(p.Item2.WeaponType == 0 ? p.Item2.Armor().ToString() : p.Item2.Weapon().ToString())})"))
|
||||
.OrderBy(p => p.Item1));
|
||||
foreach (var type in Enum.GetValues<FullEquipType>().Skip(1))
|
||||
{
|
||||
DebugTab.DrawNameTable(type.ToName(), ref _itemFilter,
|
||||
_items.ItemService.AwaitedService[type]
|
||||
.Select(p => (p.ItemId.Id, $"{p.Name} ({(p.WeaponType == 0 ? p.Armor().ToString() : p.Weapon().ToString())})")));
|
||||
}
|
||||
}
|
||||
}
|
||||
63
Glamourer/Gui/Tabs/DebugTab/ItemUnlockPanel.cs
Normal file
63
Glamourer/Gui/Tabs/DebugTab/ItemUnlockPanel.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class ItemUnlockPanel(ItemUnlockManager _itemUnlocks, ItemManager _items) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Unlocked Items";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var table = ImRaii.Table("itemUnlocks", 5,
|
||||
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.BordersOuter,
|
||||
new Vector2(ImGui.GetContentRegionAvail().X, 12 * ImGui.GetTextLineHeight()));
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGui.TableSetupColumn("ItemId", ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed, 400 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Slot", ImGuiTableColumnFlags.WidthFixed, 120 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Model", ImGuiTableColumnFlags.WidthFixed, 80 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Unlock", ImGuiTableColumnFlags.WidthFixed, 120 * ImGuiHelpers.GlobalScale);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
||||
ImGui.TableNextRow();
|
||||
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks, skips, t =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
||||
if (_items.ItemService.AwaitedService.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(equip.Name);
|
||||
ImGuiUtil.DrawTableColumn(equip.Type.ToName());
|
||||
ImGuiUtil.DrawTableColumn(equip.Weapon().ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn(_itemUnlocks.IsUnlocked(t.Key, out var time)
|
||||
? time == DateTimeOffset.MinValue
|
||||
? "Always"
|
||||
: time.LocalDateTime.ToString("g")
|
||||
: "Never");
|
||||
}, _itemUnlocks.Count);
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
|
||||
}
|
||||
}
|
||||
76
Glamourer/Gui/Tabs/DebugTab/JobPanel.cs
Normal file
76
Glamourer/Gui/Tabs/DebugTab/JobPanel.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
using Glamourer.Interop;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class JobPanel(JobService _jobs) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Job Service";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
DrawJobs();
|
||||
DrawJobGroups();
|
||||
DrawValidJobGroups();
|
||||
}
|
||||
|
||||
private void DrawJobs()
|
||||
{
|
||||
using var t = ImRaii.TreeNode("Jobs");
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
using var table = ImRaii.Table("##jobs", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
foreach (var (id, job) in _jobs.Jobs)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(id.ToString("D3"));
|
||||
ImGuiUtil.DrawTableColumn(job.Name);
|
||||
ImGuiUtil.DrawTableColumn(job.Abbreviation);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawJobGroups()
|
||||
{
|
||||
using var t = ImRaii.TreeNode("All Job Groups");
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
using var table = ImRaii.Table("##groups", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
foreach (var (group, idx) in _jobs.AllJobGroups.WithIndex())
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(idx.ToString("D3"));
|
||||
ImGuiUtil.DrawTableColumn(group.Name);
|
||||
ImGuiUtil.DrawTableColumn(group.Count.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawValidJobGroups()
|
||||
{
|
||||
using var t = ImRaii.TreeNode("Valid Job Groups");
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
using var table = ImRaii.Table("##groups", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
foreach (var (id, group) in _jobs.JobGroups)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(id.ToString("D3"));
|
||||
ImGuiUtil.DrawTableColumn(group.Name);
|
||||
ImGuiUtil.DrawTableColumn(group.Count.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
286
Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs
Normal file
286
Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public unsafe class ModelEvaluationPanel(
|
||||
ObjectManager _objectManager,
|
||||
VisorService _visorService,
|
||||
UpdateSlotService _updateSlotService,
|
||||
ChangeCustomizeService _changeCustomizeService,
|
||||
CrestService _crestService) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Model Evaluation";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private int _gameObjectIndex;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
ImGui.InputInt("Game Object Index", ref _gameObjectIndex, 0, 0);
|
||||
var actor = (Actor)_objectManager.Objects.GetObjectAddress(_gameObjectIndex);
|
||||
var model = actor.Model;
|
||||
using var table = ImRaii.Table("##evaluationTable", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableHeader("Actor");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableHeader("Model");
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Address");
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(actor.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(model.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
if (actor.IsCharacter)
|
||||
{
|
||||
ImGui.TextUnformatted(actor.AsCharacter->CharacterData.ModelCharaId.ToString());
|
||||
if (actor.AsCharacter->CharacterData.TransformationId != 0)
|
||||
ImGui.TextUnformatted($"Transformation Id: {actor.AsCharacter->CharacterData.TransformationId}");
|
||||
if (actor.AsCharacter->CharacterData.ModelCharaId_2 != -1)
|
||||
ImGui.TextUnformatted($"ModelChara2 {actor.AsCharacter->CharacterData.ModelCharaId_2}");
|
||||
if (actor.AsCharacter->CharacterData.StatusEffectVFXId != 0)
|
||||
ImGui.TextUnformatted($"Status Id: {actor.AsCharacter->CharacterData.StatusEffectVFXId}");
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Mainhand");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.GetMainhand().ToString() : "No Character");
|
||||
|
||||
var (mainhand, offhand, mainModel, offModel) = model.GetWeapons(actor);
|
||||
ImGuiUtil.DrawTableColumn(mainModel.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(mainhand.ToString());
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Offhand");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.GetOffhand().ToString() : "No Character");
|
||||
ImGuiUtil.DrawTableColumn(offModel.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(offhand.ToString());
|
||||
|
||||
DrawVisor(actor, model);
|
||||
DrawHatState(actor, model);
|
||||
DrawWeaponState(actor, model);
|
||||
DrawWetness(actor, model);
|
||||
DrawEquip(actor, model);
|
||||
DrawCustomize(actor, model);
|
||||
DrawCrests(actor, model);
|
||||
}
|
||||
|
||||
private void DrawVisor(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("Visor");
|
||||
ImGuiUtil.DrawTableColumn("Visor State");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.AsCharacter->DrawData.IsVisorToggled.ToString() : "No Character");
|
||||
ImGuiUtil.DrawTableColumn(model.IsHuman ? VisorService.GetVisorState(model).ToString() : "No Human");
|
||||
ImGui.TableNextColumn();
|
||||
if (!model.IsHuman)
|
||||
return;
|
||||
|
||||
if (ImGui.SmallButton("Set True"))
|
||||
_visorService.SetVisorState(model, true);
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Set False"))
|
||||
_visorService.SetVisorState(model, false);
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Toggle"))
|
||||
_visorService.SetVisorState(model, !VisorService.GetVisorState(model));
|
||||
}
|
||||
|
||||
private void DrawHatState(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("HatState");
|
||||
ImGuiUtil.DrawTableColumn("Hat State");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter
|
||||
? actor.AsCharacter->DrawData.IsHatHidden ? "Hidden" : actor.GetArmor(EquipSlot.Head).ToString()
|
||||
: "No Character");
|
||||
ImGuiUtil.DrawTableColumn(model.IsHuman
|
||||
? model.AsHuman->Head.Value == 0 ? "No Hat" : model.GetArmor(EquipSlot.Head).ToString()
|
||||
: "No Human");
|
||||
ImGui.TableNextColumn();
|
||||
if (!model.IsHuman)
|
||||
return;
|
||||
|
||||
if (ImGui.SmallButton("Hide"))
|
||||
_updateSlotService.UpdateSlot(model, EquipSlot.Head, CharacterArmor.Empty);
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Show"))
|
||||
_updateSlotService.UpdateSlot(model, EquipSlot.Head, actor.GetArmor(EquipSlot.Head));
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Toggle"))
|
||||
_updateSlotService.UpdateSlot(model, EquipSlot.Head,
|
||||
model.AsHuman->Head.Value == 0 ? actor.GetArmor(EquipSlot.Head) : CharacterArmor.Empty);
|
||||
}
|
||||
|
||||
private void DrawWeaponState(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("WeaponState");
|
||||
ImGuiUtil.DrawTableColumn("Weapon State");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter
|
||||
? actor.AsCharacter->DrawData.IsWeaponHidden ? "Hidden" : "Visible"
|
||||
: "No Character");
|
||||
var text = string.Empty;
|
||||
|
||||
if (!model.IsHuman)
|
||||
{
|
||||
text = "No Model";
|
||||
}
|
||||
else if (model.AsDrawObject->Object.ChildObject == null)
|
||||
{
|
||||
text = "No Weapon";
|
||||
}
|
||||
else
|
||||
{
|
||||
var weapon = (DrawObject*)model.AsDrawObject->Object.ChildObject;
|
||||
if ((weapon->Flags & 0x09) == 0x09)
|
||||
text = "Visible";
|
||||
else
|
||||
text = "Hidden";
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn(text);
|
||||
ImGui.TableNextColumn();
|
||||
if (!model.IsHuman)
|
||||
return;
|
||||
}
|
||||
|
||||
private void DrawWetness(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("Wetness");
|
||||
ImGuiUtil.DrawTableColumn("Wetness");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.AsCharacter->IsGPoseWet ? "GPose" : "None" : "No Character");
|
||||
var modelString = model.IsCharacterBase
|
||||
? $"{model.AsCharacterBase->SwimmingWetness:F4} Swimming\n"
|
||||
+ $"{model.AsCharacterBase->WeatherWetness:F4} Weather\n"
|
||||
+ $"{model.AsCharacterBase->ForcedWetness:F4} Forced\n"
|
||||
+ $"{model.AsCharacterBase->WetnessDepth:F4} Depth\n"
|
||||
: "No CharacterBase";
|
||||
ImGuiUtil.DrawTableColumn(modelString);
|
||||
ImGui.TableNextColumn();
|
||||
if (!actor.IsCharacter)
|
||||
return;
|
||||
|
||||
if (ImGui.SmallButton("GPose On"))
|
||||
actor.AsCharacter->IsGPoseWet = true;
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("GPose Off"))
|
||||
actor.AsCharacter->IsGPoseWet = false;
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("GPose Toggle"))
|
||||
actor.AsCharacter->IsGPoseWet = !actor.AsCharacter->IsGPoseWet;
|
||||
}
|
||||
|
||||
private void DrawEquip(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("Equipment");
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
using var id2 = ImRaii.PushId((int)slot);
|
||||
ImGuiUtil.DrawTableColumn(slot.ToName());
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.GetArmor(slot).ToString() : "No Character");
|
||||
ImGuiUtil.DrawTableColumn(model.IsHuman ? model.GetArmor(slot).ToString() : "No Human");
|
||||
ImGui.TableNextColumn();
|
||||
if (!model.IsHuman)
|
||||
continue;
|
||||
|
||||
if (ImGui.SmallButton("Change Piece"))
|
||||
_updateSlotService.UpdateArmor(model, slot,
|
||||
new CharacterArmor((SetId)(slot == EquipSlot.Hands ? 6064 : slot == EquipSlot.Head ? 6072 : 1), 1, 0));
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Change Stain"))
|
||||
_updateSlotService.UpdateStain(model, slot, 5);
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Reset"))
|
||||
_updateSlotService.UpdateSlot(model, slot, actor.GetArmor(slot));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCustomize(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("Customize");
|
||||
var actorCustomize = new Customize(actor.IsCharacter
|
||||
? *(Penumbra.GameData.Structs.CustomizeData*)&actor.AsCharacter->DrawData.CustomizeData
|
||||
: new Penumbra.GameData.Structs.CustomizeData());
|
||||
var modelCustomize = new Customize(model.IsHuman
|
||||
? *(Penumbra.GameData.Structs.CustomizeData*)model.AsHuman->Customize.Data
|
||||
: new Penumbra.GameData.Structs.CustomizeData());
|
||||
foreach (var type in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
using var id2 = ImRaii.PushId((int)type);
|
||||
ImGuiUtil.DrawTableColumn(type.ToDefaultName());
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actorCustomize[type].Value.ToString("X2") : "No Character");
|
||||
ImGuiUtil.DrawTableColumn(model.IsHuman ? modelCustomize[type].Value.ToString("X2") : "No Human");
|
||||
ImGui.TableNextColumn();
|
||||
if (!model.IsHuman || type.ToFlag().RequiresRedraw())
|
||||
continue;
|
||||
|
||||
if (ImGui.SmallButton("++"))
|
||||
{
|
||||
var value = modelCustomize[type].Value;
|
||||
var (_, mask) = type.ToByteAndMask();
|
||||
var shift = BitOperations.TrailingZeroCount(mask);
|
||||
var newValue = value + (1 << shift);
|
||||
modelCustomize.Set(type, (CustomizeValue)newValue);
|
||||
_changeCustomizeService.UpdateCustomize(model, modelCustomize.Data);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("--"))
|
||||
{
|
||||
var value = modelCustomize[type].Value;
|
||||
var (_, mask) = type.ToByteAndMask();
|
||||
var shift = BitOperations.TrailingZeroCount(mask);
|
||||
var newValue = value - (1 << shift);
|
||||
modelCustomize.Set(type, (CustomizeValue)newValue);
|
||||
_changeCustomizeService.UpdateCustomize(model, modelCustomize.Data);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Reset"))
|
||||
{
|
||||
modelCustomize.Set(type, actorCustomize[type]);
|
||||
_changeCustomizeService.UpdateCustomize(model, modelCustomize.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCrests(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("Crests");
|
||||
CrestFlag whichToggle = 0;
|
||||
CrestFlag totalModelFlags = 0;
|
||||
foreach (var crestFlag in CrestExtensions.AllRelevantSet)
|
||||
{
|
||||
id.Push((int)crestFlag);
|
||||
var modelCrest = CrestService.GetModelCrest(actor, crestFlag);
|
||||
if (modelCrest)
|
||||
totalModelFlags |= crestFlag;
|
||||
ImGuiUtil.DrawTableColumn($"{crestFlag.ToLabel()} Crest");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.GetCrest(crestFlag).ToString() : "No Character");
|
||||
ImGuiUtil.DrawTableColumn(modelCrest.ToString());
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
if (model.IsHuman && ImGui.SmallButton("Toggle"))
|
||||
whichToggle = crestFlag;
|
||||
|
||||
id.Pop();
|
||||
}
|
||||
|
||||
if (whichToggle != 0)
|
||||
_crestService.UpdateCrests(actor, totalModelFlags ^ whichToggle);
|
||||
}
|
||||
}
|
||||
92
Glamourer/Gui/Tabs/DebugTab/NpcAppearancePanel.cs
Normal file
92
Glamourer/Gui/Tabs/DebugTab/NpcAppearancePanel.cs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectManager _objectManager, DesignConverter _designConverter) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "NPC Appearance";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private string _npcFilter = string.Empty;
|
||||
private bool _customizeOrGear = false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
ImGui.Checkbox("Compare Customize (or Gear)", ref _customizeOrGear);
|
||||
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
|
||||
ImGui.InputTextWithHint("##npcFilter", "Filter...", ref _npcFilter, 64);
|
||||
|
||||
using var table = ImRaii.Table("npcs", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit,
|
||||
new Vector2(-1, 400 * ImGuiHelpers.GlobalScale));
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGui.TableSetupColumn("Button", ImGuiTableColumnFlags.WidthFixed);
|
||||
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed, ImGuiHelpers.GlobalScale * 300);
|
||||
ImGui.TableSetupColumn("Kind", ImGuiTableColumnFlags.WidthFixed);
|
||||
ImGui.TableSetupColumn("Visor", ImGuiTableColumnFlags.WidthFixed);
|
||||
ImGui.TableSetupColumn("Compare", ImGuiTableColumnFlags.WidthStretch);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetFrameHeightWithSpacing());
|
||||
ImGui.TableNextRow();
|
||||
var idx = 0;
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(_npcCombo.Items, skips,
|
||||
d => d.Name.Contains(_npcFilter, StringComparison.OrdinalIgnoreCase), Draw);
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetFrameHeightWithSpacing());
|
||||
|
||||
|
||||
return;
|
||||
|
||||
void Draw(CustomizationNpcOptions.NpcData data)
|
||||
{
|
||||
using var id = ImRaii.PushId(idx++);
|
||||
var disabled = !_state.GetOrCreate(_objectManager.Player, out var state);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGuiUtil.DrawDisabledButton("Apply", Vector2.Zero, string.Empty, disabled, false))
|
||||
{
|
||||
foreach (var (slot, item, stain) in _designConverter.FromDrawData(data.Equip.ToArray(), data.Mainhand, data.Offhand))
|
||||
_state.ChangeEquip(state!, slot, item, stain, StateChanged.Source.Manual);
|
||||
_state.ChangeVisorState(state!, data.VisorToggled, StateChanged.Source.Manual);
|
||||
_state.ChangeCustomize(state!, data.Customize, CustomizeFlagExtensions.All, StateChanged.Source.Manual);
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(data.Name);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(data.Kind is ObjectKind.BattleNpc ? "B" : "E");
|
||||
|
||||
using (var icon = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(data.VisorToggled ? FontAwesomeIcon.Check.ToIconString() : FontAwesomeIcon.Times.ToIconString());
|
||||
}
|
||||
|
||||
using var mono = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(_customizeOrGear ? data.Customize.Data.ToString() : data.WriteGear());
|
||||
}
|
||||
}
|
||||
}
|
||||
85
Glamourer/Gui/Tabs/DebugTab/ObjectManagerPanel.cs
Normal file
85
Glamourer/Gui/Tabs/DebugTab/ObjectManagerPanel.cs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class ObjectManagerPanel(ObjectManager _objectManager, ActorService _actors) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Object Manager";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private string _objectFilter = string.Empty;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
_objectManager.Update();
|
||||
using (var table = ImRaii.Table("##data", 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit))
|
||||
{
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Last Update");
|
||||
ImGuiUtil.DrawTableColumn(_objectManager.LastUpdate.ToString(CultureInfo.InvariantCulture));
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("World");
|
||||
ImGuiUtil.DrawTableColumn(_actors.Valid ? _actors.AwaitedService.Data.ToWorldName(_objectManager.World) : "Service Missing");
|
||||
ImGuiUtil.DrawTableColumn(_objectManager.World.ToString());
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Player Character");
|
||||
ImGuiUtil.DrawTableColumn($"{_objectManager.Player.Utf8Name} ({_objectManager.Player.Index})");
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(_objectManager.Player.ToString());
|
||||
|
||||
ImGuiUtil.DrawTableColumn("In GPose");
|
||||
ImGuiUtil.DrawTableColumn(_objectManager.IsInGPose.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
if (_objectManager.IsInGPose)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn("GPose Player");
|
||||
ImGuiUtil.DrawTableColumn($"{_objectManager.GPosePlayer.Utf8Name} ({_objectManager.GPosePlayer.Index})");
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(_objectManager.GPosePlayer.ToString());
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Number of Players");
|
||||
ImGuiUtil.DrawTableColumn(_objectManager.Count.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
}
|
||||
|
||||
var filterChanged = ImGui.InputTextWithHint("##Filter", "Filter...", ref _objectFilter, 64);
|
||||
using var table2 = ImRaii.Table("##data2", 3,
|
||||
ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersOuter | ImGuiTableFlags.ScrollY,
|
||||
new Vector2(-1, 20 * ImGui.GetTextLineHeightWithSpacing()));
|
||||
if (!table2)
|
||||
return;
|
||||
|
||||
if (filterChanged)
|
||||
ImGui.SetScrollY(0);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
||||
ImGui.TableNextRow();
|
||||
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(_objectManager, skips,
|
||||
p => p.Value.Label.Contains(_objectFilter, StringComparison.OrdinalIgnoreCase), p
|
||||
=>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(p.Key.ToString());
|
||||
ImGuiUtil.DrawTableColumn(p.Value.Label);
|
||||
ImGuiUtil.DrawTableColumn(string.Join(", ", p.Value.Objects.OrderBy(a => a.Index).Select(a => a.Index.ToString())));
|
||||
});
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeightWithSpacing());
|
||||
}
|
||||
}
|
||||
93
Glamourer/Gui/Tabs/DebugTab/PenumbraPanel.cs
Normal file
93
Glamourer/Gui/Tabs/DebugTab/PenumbraPanel.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Gui.Tabs.DebugTab;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Interop.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public unsafe class PenumbraPanel(PenumbraService _penumbra, PenumbraChangedItemTooltip _penumbraTooltip) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Penumbra Interop";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private int _gameObjectIndex;
|
||||
private Model _drawObject = Model.Null;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (!ImGui.CollapsingHeader("Penumbra"))
|
||||
return;
|
||||
|
||||
using var table = ImRaii.Table("##PenumbraTable", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Available");
|
||||
ImGuiUtil.DrawTableColumn(_penumbra.Available.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGui.SmallButton("Unattach"))
|
||||
_penumbra.Unattach();
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Reattach"))
|
||||
_penumbra.Reattach();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Draw Object");
|
||||
ImGui.TableNextColumn();
|
||||
var address = _drawObject.Address;
|
||||
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputScalar("##drawObjectPtr", ImGuiDataType.U64, (nint)(&address), nint.Zero, nint.Zero, "%llx",
|
||||
ImGuiInputTextFlags.CharsHexadecimal))
|
||||
_drawObject = address;
|
||||
ImGuiUtil.DrawTableColumn(_penumbra.Available
|
||||
? $"0x{_penumbra.GameObjectFromDrawObject(_drawObject).Address:X}"
|
||||
: "Penumbra Unavailable");
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Cutscene Object");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.InputInt("##CutsceneIndex", ref _gameObjectIndex, 0, 0);
|
||||
ImGuiUtil.DrawTableColumn(_penumbra.Available
|
||||
? _penumbra.CutsceneParent(_gameObjectIndex).ToString()
|
||||
: "Penumbra Unavailable");
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Redraw Object");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.InputInt("##redrawObject", ref _gameObjectIndex, 0, 0);
|
||||
ImGui.TableNextColumn();
|
||||
using (var disabled = ImRaii.Disabled(!_penumbra.Available))
|
||||
{
|
||||
if (ImGui.SmallButton("Redraw"))
|
||||
_penumbra.RedrawObject((ObjectIndex)_gameObjectIndex, RedrawType.Redraw);
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Last Tooltip Date");
|
||||
ImGuiUtil.DrawTableColumn(_penumbraTooltip.LastTooltip > DateTime.MinValue ? _penumbraTooltip.LastTooltip.ToLongTimeString() : "Never");
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Last Click Date");
|
||||
ImGuiUtil.DrawTableColumn(_penumbraTooltip.LastClick > DateTime.MinValue ? _penumbraTooltip.LastClick.ToLongTimeString() : "Never");
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Separator();
|
||||
foreach (var (slot, item) in _penumbraTooltip.LastItems)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn($"{slot.ToName()} Revert-Item");
|
||||
ImGuiUtil.DrawTableColumn(item.Valid ? item.Name : "None");
|
||||
ImGui.TableNextColumn();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Glamourer/Gui/Tabs/DebugTab/RestrictedGearPanel.cs
Normal file
42
Glamourer/Gui/Tabs/DebugTab/RestrictedGearPanel.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class RestrictedGearPanel(ItemManager _items) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Restricted Gear Service";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private int _setId;
|
||||
private int _secondaryId;
|
||||
private int _variant;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted("Resolve Model");
|
||||
DebugTab.DrawInputModelSet(false, ref _setId, ref _secondaryId, ref _variant);
|
||||
foreach (var race in Enum.GetValues<Race>().Skip(1))
|
||||
{
|
||||
ReadOnlySpan<Gender> genders = [Gender.Male, Gender.Female];
|
||||
foreach (var gender in genders)
|
||||
{
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var (replaced, model) =
|
||||
_items.RestrictedGear.ResolveRestricted(new CharacterArmor((SetId)_setId, (Variant)_variant, 0), slot, race, gender);
|
||||
if (replaced)
|
||||
ImGui.TextUnformatted($"{race.ToName()} - {gender} - {slot.ToName()} resolves to {model}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Glamourer/Gui/Tabs/DebugTab/RetainedStatePanel.cs
Normal file
26
Glamourer/Gui/Tabs/DebugTab/RetainedStatePanel.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using System.Linq;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class RetainedStatePanel(StateManager _stateManager, ObjectManager _objectManager) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Retained States (Inactive Actors)";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
foreach (var (identifier, state) in _stateManager.Where(kvp => !_objectManager.ContainsKey(kvp.Key)))
|
||||
{
|
||||
using var t = ImRaii.TreeNode(identifier.ToString());
|
||||
if (t)
|
||||
ActiveStatePanel.DrawState(_stateManager, ActorData.Invalid, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Glamourer/Gui/Tabs/DebugTab/StainPanel.cs
Normal file
53
Glamourer/Gui/Tabs/DebugTab/StainPanel.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class StainPanel(ItemManager _items) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Stain Service";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
private string _stainFilter = string.Empty;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
var resetScroll = ImGui.InputTextWithHint("##filter", "Filter...", ref _stainFilter, 256);
|
||||
var height = ImGui.GetTextLineHeightWithSpacing() + 2 * ImGui.GetStyle().CellPadding.Y;
|
||||
using var table = ImRaii.Table("##table", 4,
|
||||
ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.BordersOuter | ImGuiTableFlags.SizingFixedFit,
|
||||
new Vector2(-1, 10 * height));
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
if (resetScroll)
|
||||
ImGui.SetScrollY(0);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(height);
|
||||
ImGui.TableNextRow();
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(_items.Stains, skips,
|
||||
p => p.Key.Id.ToString().Contains(_stainFilter) || p.Value.Name.Contains(_stainFilter, StringComparison.OrdinalIgnoreCase),
|
||||
p =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(p.Key.Id.ToString("D3"));
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.GetWindowDrawList().AddRectFilled(ImGui.GetCursorScreenPos(),
|
||||
ImGui.GetCursorScreenPos() + new Vector2(ImGui.GetTextLineHeight()),
|
||||
p.Value.RgbaColor, 5 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight()));
|
||||
ImGuiUtil.DrawTableColumn(p.Value.Name);
|
||||
ImGuiUtil.DrawTableColumn($"#{p.Value.R:X2}{p.Value.G:X2}{p.Value.B:X2}{(p.Value.Gloss ? ", Glossy" : string.Empty)}");
|
||||
});
|
||||
ImGuiClip.DrawEndDummy(remainder, height);
|
||||
}
|
||||
}
|
||||
65
Glamourer/Gui/Tabs/DebugTab/UnlockableItemsPanel.cs
Normal file
65
Glamourer/Gui/Tabs/DebugTab/UnlockableItemsPanel.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class UnlockableItemsPanel(ItemUnlockManager _itemUnlocks, ItemManager _items) : IDebugTabTree
|
||||
{
|
||||
public string Label
|
||||
=> "Unlockable Items";
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var table = ImRaii.Table("unlockableItem", 6,
|
||||
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.BordersOuter,
|
||||
new Vector2(ImGui.GetContentRegionAvail().X, 12 * ImGui.GetTextLineHeight()));
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGui.TableSetupColumn("ItemId", ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed, 400 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Slot", ImGuiTableColumnFlags.WidthFixed, 120 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Model", ImGuiTableColumnFlags.WidthFixed, 80 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Unlock", ImGuiTableColumnFlags.WidthFixed, 120 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableSetupColumn("Criteria", ImGuiTableColumnFlags.WidthStretch);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
||||
ImGui.TableNextRow();
|
||||
var remainder = ImGuiClip.ClippedDraw(_itemUnlocks.Unlockable, skips, t =>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(t.Key.ToString());
|
||||
if (_items.ItemService.AwaitedService.TryGetValue(t.Key, EquipSlot.MainHand, out var equip))
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(equip.Name);
|
||||
ImGuiUtil.DrawTableColumn(equip.Type.ToName());
|
||||
ImGuiUtil.DrawTableColumn(equip.Weapon().ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn(_itemUnlocks.IsUnlocked(t.Key, out var time)
|
||||
? time == DateTimeOffset.MinValue
|
||||
? "Always"
|
||||
: time.LocalDateTime.ToString("g")
|
||||
: "Never");
|
||||
ImGuiUtil.DrawTableColumn(t.Value.ToString());
|
||||
}, _itemUnlocks.Unlockable.Count);
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
|
||||
}
|
||||
}
|
||||
36
Glamourer/Gui/Tabs/NpcCombo.cs
Normal file
36
Glamourer/Gui/Tabs/NpcCombo.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Services;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData;
|
||||
|
||||
namespace Glamourer.Gui.Tabs;
|
||||
|
||||
public class NpcCombo(ActorService actorManager, IdentifierService identifier, IDataManager data)
|
||||
: FilterComboBase<CustomizationNpcOptions.NpcData>(new LazyList(actorManager, identifier, data), false, Glamourer.Log)
|
||||
{
|
||||
private class LazyList(ActorService actorManager, IdentifierService identifier, IDataManager data)
|
||||
: IReadOnlyList<CustomizationNpcOptions.NpcData>
|
||||
{
|
||||
private readonly Task<IReadOnlyList<CustomizationNpcOptions.NpcData>> _task
|
||||
= Task.Run(() => CustomizationNpcOptions.CreateNpcData(actorManager.AwaitedService.Data.ENpcs, actorManager.AwaitedService.Data.BNpcs, identifier.AwaitedService, data));
|
||||
|
||||
public IEnumerator<CustomizationNpcOptions.NpcData> GetEnumerator()
|
||||
=> _task.Result.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public int Count
|
||||
=> _task.Result.Count;
|
||||
|
||||
public CustomizationNpcOptions.NpcData this[int index]
|
||||
=> _task.Result[index];
|
||||
}
|
||||
|
||||
protected override string ToString(CustomizationNpcOptions.NpcData obj)
|
||||
=> obj.Name;
|
||||
}
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
using Dalamud.Plugin;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Dalamud.Plugin;
|
||||
using Glamourer.Api;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Designs;
|
||||
|
|
@ -9,6 +12,7 @@ using Glamourer.Gui.Equipment;
|
|||
using Glamourer.Gui.Tabs;
|
||||
using Glamourer.Gui.Tabs.ActorTab;
|
||||
using Glamourer.Gui.Tabs.AutomationTab;
|
||||
using Glamourer.Gui.Tabs.DebugTab;
|
||||
using Glamourer.Gui.Tabs.DesignTab;
|
||||
using Glamourer.Gui.Tabs.UnlocksTab;
|
||||
using Glamourer.Interop;
|
||||
|
|
@ -37,7 +41,8 @@ public static class ServiceManager
|
|||
.AddDesigns()
|
||||
.AddState()
|
||||
.AddUi()
|
||||
.AddApi();
|
||||
.AddApi()
|
||||
.AddDebug();
|
||||
|
||||
return services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
|
||||
}
|
||||
|
|
@ -149,7 +154,17 @@ public static class ServiceManager
|
|||
.AddSingleton<IdentifierDrawer>()
|
||||
.AddSingleton<GlamourerChangelog>()
|
||||
.AddSingleton<DesignQuickBar>()
|
||||
.AddSingleton<DesignColorUi>();
|
||||
.AddSingleton<DesignColorUi>()
|
||||
.AddSingleton<NpcCombo>();
|
||||
|
||||
private static IServiceCollection AddDebug(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton(p => new DebugTab(p));
|
||||
var iType = typeof(IDebugTabTree);
|
||||
foreach (var type in Assembly.GetAssembly(iType)!.GetTypes().Where(t => !t.IsInterface && iType.IsAssignableFrom(t)))
|
||||
services.AddSingleton(type);
|
||||
return services;
|
||||
}
|
||||
|
||||
private static IServiceCollection AddApi(this IServiceCollection services)
|
||||
=> services.AddSingleton<CommandService>()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue