mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-15 05:04:16 +01:00
Rework some stuff, add debug tab.
This commit is contained in:
parent
668d4c033f
commit
358e33346f
6 changed files with 129 additions and 53 deletions
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace Glamourer.Structs;
|
namespace Glamourer.Structs;
|
||||||
|
|
@ -23,17 +22,22 @@ public enum CrestFlag : ushort
|
||||||
OffHand = 0x0800,
|
OffHand = 0x0800,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum CrestType : byte
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Human,
|
||||||
|
Mainhand,
|
||||||
|
Offhand,
|
||||||
|
};
|
||||||
|
|
||||||
public static class CrestExtensions
|
public static class CrestExtensions
|
||||||
{
|
{
|
||||||
public const CrestFlag All = (CrestFlag)(((ulong)EquipFlag.Offhand << 1) - 1);
|
public const CrestFlag All = (CrestFlag)(((ulong)EquipFlag.Offhand << 1) - 1);
|
||||||
public const CrestFlag AllRelevant = CrestFlag.Head | CrestFlag.Body | CrestFlag.OffHand;
|
public const CrestFlag AllRelevant = CrestFlag.Head | CrestFlag.Body | CrestFlag.OffHand;
|
||||||
|
|
||||||
public static readonly IReadOnlyList<CrestFlag> AllRelevantSet = Enum.GetValues<CrestFlag>().Where(f => f.ToRelevantIndex() >= 0).ToArray();
|
public static readonly IReadOnlyList<CrestFlag> AllRelevantSet = Enum.GetValues<CrestFlag>().Where(f => AllRelevant.HasFlag(f)).ToArray();
|
||||||
|
|
||||||
public static int ToIndex(this CrestFlag flag)
|
public static int ToInternalIndex(this CrestFlag flag)
|
||||||
=> BitOperations.TrailingZeroCount((uint)flag);
|
|
||||||
|
|
||||||
public static int ToRelevantIndex(this CrestFlag flag)
|
|
||||||
=> flag switch
|
=> flag switch
|
||||||
{
|
{
|
||||||
CrestFlag.Head => 0,
|
CrestFlag.Head => 0,
|
||||||
|
|
@ -42,6 +46,24 @@ public static class CrestExtensions
|
||||||
_ => -1,
|
_ => -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static (CrestType Type, byte Index) ToIndex(this CrestFlag flag)
|
||||||
|
=> flag switch
|
||||||
|
{
|
||||||
|
CrestFlag.Head => (CrestType.Human, 0),
|
||||||
|
CrestFlag.Body => (CrestType.Human, 1),
|
||||||
|
CrestFlag.Hands => (CrestType.Human, 2),
|
||||||
|
CrestFlag.Legs => (CrestType.Human, 3),
|
||||||
|
CrestFlag.Feet => (CrestType.Human, 4),
|
||||||
|
CrestFlag.Ears => (CrestType.None, 0),
|
||||||
|
CrestFlag.Neck => (CrestType.None, 0),
|
||||||
|
CrestFlag.Wrists => (CrestType.None, 0),
|
||||||
|
CrestFlag.RFinger => (CrestType.None, 0),
|
||||||
|
CrestFlag.LFinger => (CrestType.None, 0),
|
||||||
|
CrestFlag.MainHand => (CrestType.None, 0),
|
||||||
|
CrestFlag.OffHand => (CrestType.Offhand, 0),
|
||||||
|
_ => (CrestType.None, 0),
|
||||||
|
};
|
||||||
|
|
||||||
public static CrestFlag ToCrestFlag(this EquipSlot slot)
|
public static CrestFlag ToCrestFlag(this EquipSlot slot)
|
||||||
=> slot switch
|
=> slot switch
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
using Glamourer.Structs;
|
||||||
using Glamourer.Unlocks;
|
using Glamourer.Unlocks;
|
||||||
using Glamourer.Utility;
|
using Glamourer.Utility;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
@ -43,6 +44,7 @@ public unsafe class DebugTab : ITab
|
||||||
private readonly VisorService _visorService;
|
private readonly VisorService _visorService;
|
||||||
private readonly ChangeCustomizeService _changeCustomizeService;
|
private readonly ChangeCustomizeService _changeCustomizeService;
|
||||||
private readonly UpdateSlotService _updateSlotService;
|
private readonly UpdateSlotService _updateSlotService;
|
||||||
|
private readonly CrestService _crestService;
|
||||||
private readonly WeaponService _weaponService;
|
private readonly WeaponService _weaponService;
|
||||||
private readonly MetaService _metaService;
|
private readonly MetaService _metaService;
|
||||||
private readonly InventoryService _inventoryService;
|
private readonly InventoryService _inventoryService;
|
||||||
|
|
@ -50,7 +52,7 @@ public unsafe class DebugTab : ITab
|
||||||
private readonly ObjectManager _objectManager;
|
private readonly ObjectManager _objectManager;
|
||||||
private readonly GlamourerIpc _ipc;
|
private readonly GlamourerIpc _ipc;
|
||||||
private readonly CodeService _code;
|
private readonly CodeService _code;
|
||||||
private readonly ImportService _importService;
|
private readonly ImportService _importService;
|
||||||
|
|
||||||
private readonly ItemManager _items;
|
private readonly ItemManager _items;
|
||||||
private readonly ActorService _actors;
|
private readonly ActorService _actors;
|
||||||
|
|
@ -82,7 +84,7 @@ public unsafe class DebugTab : ITab
|
||||||
PenumbraChangedItemTooltip penumbraTooltip, MetaService metaService, GlamourerIpc ipc, DalamudPluginInterface pluginInterface,
|
PenumbraChangedItemTooltip penumbraTooltip, MetaService metaService, GlamourerIpc ipc, DalamudPluginInterface pluginInterface,
|
||||||
AutoDesignManager autoDesignManager, JobService jobs, CodeService code, CustomizeUnlockManager customizeUnlocks,
|
AutoDesignManager autoDesignManager, JobService jobs, CodeService code, CustomizeUnlockManager customizeUnlocks,
|
||||||
ItemUnlockManager itemUnlocks, DesignConverter designConverter, ImportService importService, InventoryService inventoryService,
|
ItemUnlockManager itemUnlocks, DesignConverter designConverter, ImportService importService, InventoryService inventoryService,
|
||||||
HumanModelList humans, FunModule funModule)
|
HumanModelList humans, FunModule funModule, CrestService crestService)
|
||||||
{
|
{
|
||||||
_changeCustomizeService = changeCustomizeService;
|
_changeCustomizeService = changeCustomizeService;
|
||||||
_visorService = visorService;
|
_visorService = visorService;
|
||||||
|
|
@ -107,10 +109,11 @@ public unsafe class DebugTab : ITab
|
||||||
_customizeUnlocks = customizeUnlocks;
|
_customizeUnlocks = customizeUnlocks;
|
||||||
_itemUnlocks = itemUnlocks;
|
_itemUnlocks = itemUnlocks;
|
||||||
_designConverter = designConverter;
|
_designConverter = designConverter;
|
||||||
_importService = importService;
|
_importService = importService;
|
||||||
_inventoryService = inventoryService;
|
_inventoryService = inventoryService;
|
||||||
_humans = humans;
|
_humans = humans;
|
||||||
_funModule = funModule;
|
_funModule = funModule;
|
||||||
|
_crestService = crestService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
|
|
@ -200,6 +203,7 @@ public unsafe class DebugTab : ITab
|
||||||
DrawWetness(actor, model);
|
DrawWetness(actor, model);
|
||||||
DrawEquip(actor, model);
|
DrawEquip(actor, model);
|
||||||
DrawCustomize(actor, model);
|
DrawCustomize(actor, model);
|
||||||
|
DrawCrests(actor, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string _objectFilter = string.Empty;
|
private string _objectFilter = string.Empty;
|
||||||
|
|
@ -477,6 +481,25 @@ public unsafe class DebugTab : ITab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawCrests(Actor actor, Model model)
|
||||||
|
{
|
||||||
|
using var id = ImRaii.PushId("Crests");
|
||||||
|
foreach (var crestFlag in CrestExtensions.AllRelevantSet)
|
||||||
|
{
|
||||||
|
id.Push((int)crestFlag);
|
||||||
|
var modelCrest = CrestService.GetModelCrest(actor, 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"))
|
||||||
|
_crestService.UpdateCrest(actor, crestFlag, !modelCrest);
|
||||||
|
|
||||||
|
id.Pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Penumbra
|
#region Penumbra
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Dalamud.Utility.Signatures;
|
using Dalamud.Utility.Signatures;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
|
using Glamourer.Structs;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
|
|
@ -27,6 +30,7 @@ public sealed unsafe class CrestService : EventWrapper<Action<Model, EquipSlot,
|
||||||
public CrestService(IGameInteropProvider interop)
|
public CrestService(IGameInteropProvider interop)
|
||||||
: base(nameof(CrestService))
|
: base(nameof(CrestService))
|
||||||
{
|
{
|
||||||
|
interop.InitializeFromAttributes(this);
|
||||||
_humanSetFreeCompanyCrestVisibleOnSlot =
|
_humanSetFreeCompanyCrestVisibleOnSlot =
|
||||||
interop.HookFromAddress<SetCrestDelegateIntern>(_humanVTable[96], HumanSetFreeCompanyCrestVisibleOnSlotDetour);
|
interop.HookFromAddress<SetCrestDelegateIntern>(_humanVTable[96], HumanSetFreeCompanyCrestVisibleOnSlotDetour);
|
||||||
_weaponSetFreeCompanyCrestVisibleOnSlot =
|
_weaponSetFreeCompanyCrestVisibleOnSlot =
|
||||||
|
|
@ -48,10 +52,68 @@ public sealed unsafe class CrestService : EventWrapper<Action<Model, EquipSlot,
|
||||||
visible = ret;
|
visible = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateCrest(Model drawObject, EquipSlot slot, bool crest)
|
public static bool GetModelCrest(Actor gameObject, CrestFlag slot)
|
||||||
{
|
{
|
||||||
using var _ = _inUpdate.EnterMethod();
|
if (!gameObject.IsCharacter)
|
||||||
drawObject.SetFreeCompanyCrestVisibleOnSlot(slot, crest);
|
return false;
|
||||||
|
|
||||||
|
var (type, index) = slot.ToIndex();
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case CrestType.Human:
|
||||||
|
{
|
||||||
|
var model = gameObject.Model;
|
||||||
|
if (!model.IsHuman)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var getter = (delegate* unmanaged<Human*, byte, byte>)((nint*)model.AsCharacterBase->VTable)[95];
|
||||||
|
return getter(model.AsHuman, index) != 0;
|
||||||
|
}
|
||||||
|
case CrestType.Offhand:
|
||||||
|
{
|
||||||
|
var model = (Model)gameObject.AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.OffHand).DrawObject;
|
||||||
|
if (!model.IsWeapon)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var getter = (delegate* unmanaged<Weapon*, byte, byte>)((nint*)model.AsCharacterBase->VTable)[95];
|
||||||
|
return getter(model.AsWeapon, index) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateCrest(Actor gameObject, CrestFlag slot, bool crest)
|
||||||
|
{
|
||||||
|
if (!gameObject.IsCharacter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var (type, index) = slot.ToIndex();
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case CrestType.Human:
|
||||||
|
{
|
||||||
|
var model = gameObject.Model;
|
||||||
|
if (!model.IsHuman)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var _ = _inUpdate.EnterMethod();
|
||||||
|
var setter = (delegate* unmanaged<Human*, byte, byte, void>)((nint*)model.AsCharacterBase->VTable)[96];
|
||||||
|
setter(model.AsHuman, index, crest ? (byte)1 : (byte)0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CrestType.Offhand:
|
||||||
|
{
|
||||||
|
var model = (Model)gameObject.AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.OffHand).DrawObject;
|
||||||
|
if (!model.IsWeapon)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var _ = _inUpdate.EnterMethod();
|
||||||
|
var setter = (delegate* unmanaged<Weapon*, byte, byte, void>)((nint*)model.AsCharacterBase->VTable)[96];
|
||||||
|
setter(model.AsWeapon, index, crest ? (byte)1 : (byte)0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly InMethodChecker _inUpdate = new();
|
private readonly InMethodChecker _inUpdate = new();
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
|
using Glamourer.Structs;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
|
|
@ -106,7 +107,7 @@ public readonly unsafe struct Actor : IEquatable<Actor>
|
||||||
public CharacterArmor GetArmor(EquipSlot slot)
|
public CharacterArmor GetArmor(EquipSlot slot)
|
||||||
=> ((CharacterArmor*)&AsCharacter->DrawData.Head)[slot.ToIndex()];
|
=> ((CharacterArmor*)&AsCharacter->DrawData.Head)[slot.ToIndex()];
|
||||||
|
|
||||||
public bool GetCrest(EquipSlot slot)
|
public bool GetCrest(CrestFlag slot)
|
||||||
=> (GetFreeCompanyCrestBitfield() & CrestMask(slot)) != 0;
|
=> (GetFreeCompanyCrestBitfield() & CrestMask(slot)) != 0;
|
||||||
|
|
||||||
public CharacterWeapon GetMainhand()
|
public CharacterWeapon GetMainhand()
|
||||||
|
|
@ -122,15 +123,15 @@ public readonly unsafe struct Actor : IEquatable<Actor>
|
||||||
private byte GetFreeCompanyCrestBitfield()
|
private byte GetFreeCompanyCrestBitfield()
|
||||||
=> ((byte*)Address)[0x1BBB];
|
=> ((byte*)Address)[0x1BBB];
|
||||||
|
|
||||||
private static byte CrestMask(EquipSlot slot)
|
private static byte CrestMask(CrestFlag slot)
|
||||||
=> slot switch
|
=> slot switch
|
||||||
{
|
{
|
||||||
EquipSlot.OffHand => 0x01,
|
CrestFlag.OffHand => 0x01,
|
||||||
EquipSlot.Head => 0x02,
|
CrestFlag.Head => 0x02,
|
||||||
EquipSlot.Body => 0x04,
|
CrestFlag.Body => 0x04,
|
||||||
EquipSlot.Hands => 0x08,
|
CrestFlag.Hands => 0x08,
|
||||||
EquipSlot.Legs => 0x10,
|
CrestFlag.Legs => 0x10,
|
||||||
EquipSlot.Feet => 0x20,
|
CrestFlag.Feet => 0x20,
|
||||||
_ => 0x00,
|
_ => 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,9 +91,6 @@ public readonly unsafe struct Model : IEquatable<Model>
|
||||||
public CharacterArmor GetArmor(EquipSlot slot)
|
public CharacterArmor GetArmor(EquipSlot slot)
|
||||||
=> ((CharacterArmor*)&AsHuman->Head)[slot.ToIndex()];
|
=> ((CharacterArmor*)&AsHuman->Head)[slot.ToIndex()];
|
||||||
|
|
||||||
public bool GetCrest(EquipSlot slot)
|
|
||||||
=> IsFreeCompanyCrestVisibleOnSlot(slot);
|
|
||||||
|
|
||||||
public Customize GetCustomize()
|
public Customize GetCustomize()
|
||||||
=> *(Customize*)&AsHuman->Customize;
|
=> *(Customize*)&AsHuman->Customize;
|
||||||
|
|
||||||
|
|
@ -198,35 +195,6 @@ public readonly unsafe struct Model : IEquatable<Model>
|
||||||
return discriminator1 == 0 && discriminator2 != 0 ? (second, first) : (first, second);
|
return discriminator1 == 0 && discriminator2 != 0 ? (second, first) : (first, second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove these when available in ClientStructs
|
|
||||||
private bool IsFreeCompanyCrestVisibleOnSlot(EquipSlot slot)
|
|
||||||
{
|
|
||||||
if (!IsCharacterBase)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var index = (byte)slot.ToIndex();
|
|
||||||
if (index >= 12)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var characterBase = AsCharacterBase;
|
|
||||||
var getter = (delegate* unmanaged<CharacterBase*, byte, byte>)((nint*)characterBase->VTable)[95];
|
|
||||||
return getter(characterBase, index) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetFreeCompanyCrestVisibleOnSlot(EquipSlot slot, bool visible)
|
|
||||||
{
|
|
||||||
if (!IsCharacterBase)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var index = (byte)slot.ToIndex();
|
|
||||||
if (index >= 12)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var characterBase = AsCharacterBase;
|
|
||||||
var setter = (delegate* unmanaged<CharacterBase*, byte, byte, void>)((nint*)characterBase->VTable)[96];
|
|
||||||
setter(characterBase, index, visible ? (byte)1 : (byte)0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
=> $"0x{Address:X}";
|
=> $"0x{Address:X}";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ public class ActorState
|
||||||
=> ref _sources[slot.ToIndex() + (stain ? EquipFlagExtensions.NumEquipFlags / 2 : 0)];
|
=> ref _sources[slot.ToIndex() + (stain ? EquipFlagExtensions.NumEquipFlags / 2 : 0)];
|
||||||
|
|
||||||
public ref StateChanged.Source this[CrestFlag slot]
|
public ref StateChanged.Source this[CrestFlag slot]
|
||||||
=> ref _sources[EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices + 5 + slot.ToRelevantIndex()];
|
=> ref _sources[EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices + 5 + slot.ToInternalIndex()];
|
||||||
|
|
||||||
public ref StateChanged.Source this[CustomizeIndex type]
|
public ref StateChanged.Source this[CustomizeIndex type]
|
||||||
=> ref _sources[EquipFlagExtensions.NumEquipFlags + (int)type];
|
=> ref _sources[EquipFlagExtensions.NumEquipFlags + (int)type];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue