Merge branch 'master' into HEAD

This commit is contained in:
Exter-N 2023-11-03 20:30:23 +01:00
commit c024d7e826
5 changed files with 133 additions and 111 deletions

View file

@ -42,7 +42,7 @@ public unsafe class PathState : IDisposable
MetaState = metaState;
CharacterUtility = characterUtility;
_human = new ResolvePathHooks(interop, this, _humanVTable, ResolvePathHooks.Type.Human);
_weapon = new ResolvePathHooks(interop, this, _weaponVTable, ResolvePathHooks.Type.Weapon);
_weapon = new ResolvePathHooks(interop, this, _weaponVTable, ResolvePathHooks.Type.Other);
_demiHuman = new ResolvePathHooks(interop, this, _demiHumanVTable, ResolvePathHooks.Type.Other);
_monster = new ResolvePathHooks(interop, this, _monsterVTable, ResolvePathHooks.Type.Other);
_human.Enable();

View file

@ -12,45 +12,47 @@ public unsafe class ResolvePathHooks : IDisposable
public enum Type
{
Human,
Weapon,
Other,
}
private delegate nint GeneralResolveDelegate(nint drawObject, nint path, nint unk3, uint unk4);
private delegate nint MPapResolveDelegate(nint drawObject, nint path, nint unk3, uint unk4, uint unk5);
private delegate nint MaterialResolveDelegate(nint drawObject, nint path, nint unk3, uint unk4, ulong unk5);
private delegate nint EidResolveDelegate(nint drawObject, nint path, nint unk3);
private delegate nint MPapResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex, uint sId);
private delegate nint NamedResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex, nint name);
private delegate nint PerSlotResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex);
private delegate nint SingleResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize);
private delegate nint TmbResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize, nint timelineName);
// Kept separate from NamedResolveDelegate because the 5th parameter has out semantics here, instead of in.
private delegate nint VfxResolveDelegate(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex, nint unkOutParam);
private readonly Hook<GeneralResolveDelegate> _resolveDecalPathHook;
private readonly Hook<EidResolveDelegate> _resolveEidPathHook;
private readonly Hook<GeneralResolveDelegate> _resolveImcPathHook;
private readonly Hook<MPapResolveDelegate> _resolveMPapPathHook;
private readonly Hook<GeneralResolveDelegate> _resolveMdlPathHook;
private readonly Hook<MaterialResolveDelegate> _resolveMtrlPathHook;
private readonly Hook<MaterialResolveDelegate> _resolvePapPathHook;
private readonly Hook<GeneralResolveDelegate> _resolvePhybPathHook;
private readonly Hook<GeneralResolveDelegate> _resolveSklbPathHook;
private readonly Hook<GeneralResolveDelegate> _resolveSkpPathHook;
private readonly Hook<EidResolveDelegate> _resolveTmbPathHook;
private readonly Hook<MaterialResolveDelegate> _resolveVfxPathHook;
private readonly Hook<PerSlotResolveDelegate> _resolveDecalPathHook;
private readonly Hook<SingleResolveDelegate> _resolveEidPathHook;
private readonly Hook<PerSlotResolveDelegate> _resolveImcPathHook;
private readonly Hook<MPapResolveDelegate> _resolveMPapPathHook;
private readonly Hook<PerSlotResolveDelegate> _resolveMdlPathHook;
private readonly Hook<NamedResolveDelegate> _resolveMtrlPathHook;
private readonly Hook<NamedResolveDelegate> _resolvePapPathHook;
private readonly Hook<PerSlotResolveDelegate> _resolvePhybPathHook;
private readonly Hook<PerSlotResolveDelegate> _resolveSklbPathHook;
private readonly Hook<PerSlotResolveDelegate> _resolveSkpPathHook;
private readonly Hook<TmbResolveDelegate> _resolveTmbPathHook;
private readonly Hook<VfxResolveDelegate> _resolveVfxPathHook;
private readonly PathState _parent;
public ResolvePathHooks(IGameInteropProvider interop, PathState parent, nint* vTable, Type type)
{
_parent = parent;
_resolveDecalPathHook = Create<GeneralResolveDelegate>(interop, vTable[83], type, ResolveDecalWeapon, ResolveDecal);
_resolveEidPathHook = Create<EidResolveDelegate>(interop, vTable[85], type, ResolveEidWeapon, ResolveEid);
_resolveImcPathHook = Create<GeneralResolveDelegate>(interop, vTable[81], type, ResolveImcWeapon, ResolveImc);
_resolveMPapPathHook = Create<MPapResolveDelegate>(interop, vTable[79], type, ResolveMPapWeapon, ResolveMPap);
_resolveMdlPathHook = Create<GeneralResolveDelegate>(interop, vTable[73], type, ResolveMdlWeapon, ResolveMdl, ResolveMdlHuman);
_resolveMtrlPathHook = Create<MaterialResolveDelegate>(interop, vTable[82], type, ResolveMtrlWeapon, ResolveMtrl);
_resolvePapPathHook = Create<MaterialResolveDelegate>(interop, vTable[76], type, ResolvePapWeapon, ResolvePap, ResolvePapHuman);
_resolvePhybPathHook = Create<GeneralResolveDelegate>(interop, vTable[75], type, ResolvePhybWeapon, ResolvePhyb, ResolvePhybHuman);
_resolveSklbPathHook = Create<GeneralResolveDelegate>(interop, vTable[72], type, ResolveSklbWeapon, ResolveSklb, ResolveSklbHuman);
_resolveSkpPathHook = Create<GeneralResolveDelegate>(interop, vTable[74], type, ResolveSkpWeapon, ResolveSkp, ResolveSkpHuman);
_resolveTmbPathHook = Create<EidResolveDelegate>(interop, vTable[77], type, ResolveTmbWeapon, ResolveTmb);
_resolveVfxPathHook = Create<MaterialResolveDelegate>(interop, vTable[84], type, ResolveVfxWeapon, ResolveVfx);
_resolveDecalPathHook = Create<PerSlotResolveDelegate>(interop, vTable[83], ResolveDecal);
_resolveEidPathHook = Create<SingleResolveDelegate>(interop, vTable[85], ResolveEid);
_resolveImcPathHook = Create<PerSlotResolveDelegate>(interop, vTable[81], ResolveImc);
_resolveMPapPathHook = Create<MPapResolveDelegate>(interop, vTable[79], ResolveMPap);
_resolveMdlPathHook = Create<PerSlotResolveDelegate>(interop, vTable[73], type, ResolveMdl, ResolveMdlHuman);
_resolveMtrlPathHook = Create<NamedResolveDelegate>(interop, vTable[82], ResolveMtrl);
_resolvePapPathHook = Create<NamedResolveDelegate>(interop, vTable[76], type, ResolvePap, ResolvePapHuman);
_resolvePhybPathHook = Create<PerSlotResolveDelegate>(interop, vTable[75], type, ResolvePhyb, ResolvePhybHuman);
_resolveSklbPathHook = Create<PerSlotResolveDelegate>(interop, vTable[72], type, ResolveSklb, ResolveSklbHuman);
_resolveSkpPathHook = Create<PerSlotResolveDelegate>(interop, vTable[74], type, ResolveSkp, ResolveSkpHuman);
_resolveTmbPathHook = Create<TmbResolveDelegate>(interop, vTable[77], ResolveTmb);
_resolveVfxPathHook = Create<VfxResolveDelegate>(interop, vTable[84], ResolveVfx);
}
public void Enable()
@ -101,74 +103,74 @@ public unsafe class ResolvePathHooks : IDisposable
_resolveVfxPathHook.Dispose();
}
private nint ResolveDecal(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolveDecalPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolveDecal(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex)
=> ResolvePath(drawObject, _resolveDecalPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex));
private nint ResolveEid(nint drawObject, nint path, nint unk3)
=> ResolvePath(drawObject, _resolveEidPathHook.Original(drawObject, path, unk3));
private nint ResolveEid(nint drawObject, nint pathBuffer, nint pathBufferSize)
=> ResolvePath(drawObject, _resolveEidPathHook.Original(drawObject, pathBuffer, pathBufferSize));
private nint ResolveImc(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolveImcPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolveImc(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex)
=> ResolvePath(drawObject, _resolveImcPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex));
private nint ResolveMPap(nint drawObject, nint path, nint unk3, uint unk4, uint unk5)
=> ResolvePath(drawObject, _resolveMPapPathHook.Original(drawObject, path, unk3, unk4, unk5));
private nint ResolveMPap(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex, uint unkSId)
=> ResolvePath(drawObject, _resolveMPapPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex, unkSId));
private nint ResolveMdl(nint drawObject, nint path, nint unk3, uint modelType)
=> ResolvePath(drawObject, _resolveMdlPathHook.Original(drawObject, path, unk3, modelType));
private nint ResolveMdl(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex)
=> ResolvePath(drawObject, _resolveMdlPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex));
private nint ResolveMtrl(nint drawObject, nint path, nint unk3, uint unk4, ulong unk5)
=> ResolvePath(drawObject, _resolveMtrlPathHook.Original(drawObject, path, unk3, unk4, unk5));
private nint ResolveMtrl(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex, nint mtrlFileName)
=> ResolvePath(drawObject, _resolveMtrlPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex, mtrlFileName));
private nint ResolvePap(nint drawObject, nint path, nint unk3, uint unk4, ulong unk5)
=> ResolvePath(drawObject, _resolvePapPathHook.Original(drawObject, path, unk3, unk4, unk5));
private nint ResolvePap(nint drawObject, nint pathBuffer, nint pathBufferSize, uint unkAnimationIndex, nint animationName)
=> ResolvePath(drawObject, _resolvePapPathHook.Original(drawObject, pathBuffer, pathBufferSize, unkAnimationIndex, animationName));
private nint ResolvePhyb(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolvePhybPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolvePhyb(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex)
=> ResolvePath(drawObject, _resolvePhybPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex));
private nint ResolveSklb(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolveSklbPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolveSklb(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex)
=> ResolvePath(drawObject, _resolveSklbPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex));
private nint ResolveSkp(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolveSkpPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolveSkp(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex)
=> ResolvePath(drawObject, _resolveSkpPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex));
private nint ResolveTmb(nint drawObject, nint path, nint unk3)
=> ResolvePath(drawObject, _resolveTmbPathHook.Original(drawObject, path, unk3));
private nint ResolveTmb(nint drawObject, nint pathBuffer, nint pathBufferSize, nint timelineName)
=> ResolvePath(drawObject, _resolveTmbPathHook.Original(drawObject, pathBuffer, pathBufferSize, timelineName));
private nint ResolveVfx(nint drawObject, nint path, nint unk3, uint unk4, ulong unk5)
=> ResolvePath(drawObject, _resolveVfxPathHook.Original(drawObject, path, unk3, unk4, unk5));
private nint ResolveVfx(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex, nint unkOutParam)
=> ResolvePath(drawObject, _resolveVfxPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex, unkOutParam));
private nint ResolveMdlHuman(nint drawObject, nint path, nint unk3, uint modelType)
private nint ResolveMdlHuman(nint drawObject, nint pathBuffer, nint pathBufferSize, uint slotIndex)
{
var data = _parent.CollectionResolver.IdentifyCollection((DrawObject*)drawObject, true);
using var eqdp = modelType > 9
using var eqdp = slotIndex > 9
? DisposableContainer.Empty
: _parent.MetaState.ResolveEqdpData(data.ModCollection, MetaState.GetHumanGenderRace(drawObject), modelType < 5, modelType > 4);
return ResolvePath(data, _resolveMdlPathHook.Original(drawObject, path, unk3, modelType));
: _parent.MetaState.ResolveEqdpData(data.ModCollection, MetaState.GetHumanGenderRace(drawObject), slotIndex < 5, slotIndex > 4);
return ResolvePath(data, _resolveMdlPathHook.Original(drawObject, pathBuffer, pathBufferSize, slotIndex));
}
private nint ResolvePapHuman(nint drawObject, nint path, nint unk3, uint unk4, ulong unk5)
private nint ResolvePapHuman(nint drawObject, nint pathBuffer, nint pathBufferSize, uint unkAnimationIndex, nint animationName)
{
using var est = GetEstChanges(drawObject, out var data);
return ResolvePath(data, _resolvePapPathHook.Original(drawObject, path, unk3, unk4, unk5));
return ResolvePath(data, _resolvePapPathHook.Original(drawObject, pathBuffer, pathBufferSize, unkAnimationIndex, animationName));
}
private nint ResolvePhybHuman(nint drawObject, nint path, nint unk3, uint unk4)
private nint ResolvePhybHuman(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex)
{
using var est = GetEstChanges(drawObject, out var data);
return ResolvePath(data, _resolvePhybPathHook.Original(drawObject, path, unk3, unk4));
return ResolvePath(data, _resolvePhybPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex));
}
private nint ResolveSklbHuman(nint drawObject, nint path, nint unk3, uint unk4)
private nint ResolveSklbHuman(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex)
{
using var est = GetEstChanges(drawObject, out var data);
return ResolvePath(data, _resolveSklbPathHook.Original(drawObject, path, unk3, unk4));
return ResolvePath(data, _resolveSklbPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex));
}
private nint ResolveSkpHuman(nint drawObject, nint path, nint unk3, uint unk4)
private nint ResolveSkpHuman(nint drawObject, nint pathBuffer, nint pathBufferSize, uint partialSkeletonIndex)
{
using var est = GetEstChanges(drawObject, out var data);
return ResolvePath(data, _resolveSkpPathHook.Original(drawObject, path, unk3, unk4));
return ResolvePath(data, _resolveSkpPathHook.Original(drawObject, pathBuffer, pathBufferSize, partialSkeletonIndex));
}
private DisposableContainer GetEstChanges(nint drawObject, out ResolveData data)
@ -180,58 +182,21 @@ public unsafe class ResolvePathHooks : IDisposable
data.ModCollection.TemporarilySetEstFile(_parent.CharacterUtility, EstManipulation.EstType.Head));
}
private nint ResolveDecalWeapon(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolveDecalPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolveEidWeapon(nint drawObject, nint path, nint unk3)
=> ResolvePath(drawObject, _resolveEidPathHook.Original(drawObject, path, unk3));
private nint ResolveImcWeapon(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolveImcPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolveMPapWeapon(nint drawObject, nint path, nint unk3, uint unk4, uint unk5)
=> ResolvePath(drawObject, _resolveMPapPathHook.Original(drawObject, path, unk3, unk4, unk5));
private nint ResolveMdlWeapon(nint drawObject, nint path, nint unk3, uint modelType)
=> ResolvePath(drawObject, _resolveMdlPathHook.Original(drawObject, path, unk3, modelType));
private nint ResolveMtrlWeapon(nint drawObject, nint path, nint unk3, uint unk4, ulong unk5)
=> ResolvePath(drawObject, _resolveMtrlPathHook.Original(drawObject, path, unk3, unk4, unk5));
private nint ResolvePapWeapon(nint drawObject, nint path, nint unk3, uint unk4, ulong unk5)
=> ResolvePath(drawObject, _resolvePapPathHook.Original(drawObject, path, unk3, unk4, unk5));
private nint ResolvePhybWeapon(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolvePhybPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolveSklbWeapon(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolveSklbPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolveSkpWeapon(nint drawObject, nint path, nint unk3, uint unk4)
=> ResolvePath(drawObject, _resolveSkpPathHook.Original(drawObject, path, unk3, unk4));
private nint ResolveTmbWeapon(nint drawObject, nint path, nint unk3)
=> ResolvePath(drawObject, _resolveTmbPathHook.Original(drawObject, path, unk3));
private nint ResolveVfxWeapon(nint drawObject, nint path, nint unk3, uint unk4, ulong unk5)
=> ResolvePath(drawObject, _resolveVfxPathHook.Original(drawObject, path, unk3, unk4, unk5));
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static Hook<T> Create<T>(IGameInteropProvider interop, nint address, Type type, T weapon, T other, T human) where T : Delegate
private static Hook<T> Create<T>(IGameInteropProvider interop, nint address, Type type, T other, T human) where T : Delegate
{
var del = type switch
{
Type.Human => human,
Type.Weapon => weapon,
_ => other,
};
return interop.HookFromAddress(address, del);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static Hook<T> Create<T>(IGameInteropProvider interop, nint address, Type type, T weapon, T other) where T : Delegate
=> Create(interop, address, type, weapon, other, other);
private static Hook<T> Create<T>(IGameInteropProvider interop, nint address, T del) where T : Delegate
=> interop.HookFromAddress(address, del);
// Implementation

View file

@ -18,10 +18,13 @@ public unsafe partial class RedrawService
public const int GPoseSlots = 42;
public const int GPoseEndIdx = GPosePlayerIdx + GPoseSlots;
private readonly string?[] _gPoseNames = new string?[GPoseSlots];
private readonly string?[] _gPoseNames = new string?[GPoseSlots];
private int _gPoseNameCounter;
private bool InGPose
internal IReadOnlyList<string?> GPoseNames
=> _gPoseNames;
internal bool InGPose
=> _clientState.IsGPosing;
// VFuncs that disable and enable draw, used only for GPose actors.
@ -108,6 +111,15 @@ public sealed unsafe partial class RedrawService : IDisposable
private readonly List<int> _afterGPoseQueue = new(GPoseSlots);
private int _target = -1;
internal IReadOnlyList<int> Queue
=> _queue;
internal IReadOnlyList<int> AfterGPoseQueue
=> _afterGPoseQueue;
internal int Target
=> _target;
public event GameObjectRedrawnDelegate? GameObjectRedrawn;
public RedrawService(IFramework framework, IObjectTable objects, ITargetManager targets, ICondition conditions, IClientState clientState)

View file

@ -19,6 +19,7 @@ using Penumbra.UI.Tabs;
using ChangedItemClick = Penumbra.Communication.ChangedItemClick;
using ChangedItemHover = Penumbra.Communication.ChangedItemHover;
using OtterGui.Tasks;
using Penumbra.GameData.Enums;
using Penumbra.Interop.Structs;
using Penumbra.UI;
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
@ -110,13 +111,13 @@ public class Penumbra : IDalamudPlugin
_services.GetRequiredService<PenumbraIpcProviders>();
_communicatorService.ChangedItemHover.Subscribe(it =>
{
if (it is Item)
if (it is (Item, FullEquipType))
ImGui.TextUnformatted("Left Click to create an item link in chat.");
}, ChangedItemHover.Priority.Link);
_communicatorService.ChangedItemClick.Subscribe((button, it) =>
{
if (button == MouseButton.Left && it is Item item)
if (button == MouseButton.Left && it is (Item item, FullEquipType type))
Messager.LinkItem(item);
}, ChangedItemClick.Priority.Link);
}

View file

@ -65,6 +65,7 @@ public class DebugTab : Window, ITab
private readonly TextureManager _textureManager;
private readonly SkinFixer _skinFixer;
private readonly IdentifierService _identifier;
private readonly RedrawService _redraws;
public DebugTab(StartTracker timer, PerformanceTracker performance, Configuration config, CollectionManager collectionManager,
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorService actorService,
@ -72,7 +73,7 @@ public class DebugTab : Window, ITab
ResourceManagerService resourceManager, PenumbraIpcProviders ipc, CollectionResolver collectionResolver,
DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache,
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
TextureManager textureManager, SkinFixer skinFixer, IdentifierService identifier)
TextureManager textureManager, SkinFixer skinFixer, IdentifierService identifier, RedrawService redraws)
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse)
{
IsOpen = true;
@ -107,6 +108,7 @@ public class DebugTab : Window, ITab
_textureManager = textureManager;
_skinFixer = skinFixer;
_identifier = identifier;
_redraws = redraws;
}
public ReadOnlySpan<byte> Label
@ -317,6 +319,48 @@ public class DebugTab : Window, ITab
}
}
}
using (var tree = TreeNode("Redraw Service"))
{
if (tree)
{
using var table = Table("##redraws", 3, ImGuiTableFlags.RowBg);
if (table)
{
ImGuiUtil.DrawTableColumn("In GPose");
ImGuiUtil.DrawTableColumn(_redraws.InGPose.ToString());
ImGui.TableNextColumn();
ImGuiUtil.DrawTableColumn("Target");
ImGuiUtil.DrawTableColumn(_redraws.Target.ToString());
ImGui.TableNextColumn();
foreach (var (objectIdx, idx) in _redraws.Queue.WithIndex())
{
var (actualIdx, state) = objectIdx < 0 ? (~objectIdx, "Queued") : (objectIdx, "Invisible");
ImGuiUtil.DrawTableColumn($"Redraw Queue #{idx}");
ImGuiUtil.DrawTableColumn(actualIdx.ToString());
ImGuiUtil.DrawTableColumn(state);
}
foreach (var (objectIdx, idx) in _redraws.AfterGPoseQueue.WithIndex())
{
var (actualIdx, state) = objectIdx < 0 ? (~objectIdx, "Queued") : (objectIdx, "Invisible");
ImGuiUtil.DrawTableColumn($"GPose Queue #{idx}");
ImGuiUtil.DrawTableColumn(actualIdx.ToString());
ImGuiUtil.DrawTableColumn(state);
}
foreach (var (name, idx) in _redraws.GPoseNames.OfType<string>().WithIndex())
{
ImGuiUtil.DrawTableColumn($"GPose Name #{idx}");
ImGuiUtil.DrawTableColumn(name);
ImGui.TableNextColumn();
}
}
}
}
}
private void DrawPerformanceTab()