mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-15 13:14:17 +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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Structs;
|
||||
|
|
@ -23,17 +22,22 @@ public enum CrestFlag : ushort
|
|||
OffHand = 0x0800,
|
||||
}
|
||||
|
||||
public enum CrestType : byte
|
||||
{
|
||||
None,
|
||||
Human,
|
||||
Mainhand,
|
||||
Offhand,
|
||||
};
|
||||
|
||||
public static class CrestExtensions
|
||||
{
|
||||
public const CrestFlag All = (CrestFlag)(((ulong)EquipFlag.Offhand << 1) - 1);
|
||||
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)
|
||||
=> BitOperations.TrailingZeroCount((uint)flag);
|
||||
|
||||
public static int ToRelevantIndex(this CrestFlag flag)
|
||||
public static int ToInternalIndex(this CrestFlag flag)
|
||||
=> flag switch
|
||||
{
|
||||
CrestFlag.Head => 0,
|
||||
|
|
@ -42,6 +46,24 @@ public static class CrestExtensions
|
|||
_ => -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)
|
||||
=> slot switch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ using Glamourer.Interop.Penumbra;
|
|||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using Glamourer.Unlocks;
|
||||
using Glamourer.Utility;
|
||||
using ImGuiNET;
|
||||
|
|
@ -43,6 +44,7 @@ public unsafe class DebugTab : ITab
|
|||
private readonly VisorService _visorService;
|
||||
private readonly ChangeCustomizeService _changeCustomizeService;
|
||||
private readonly UpdateSlotService _updateSlotService;
|
||||
private readonly CrestService _crestService;
|
||||
private readonly WeaponService _weaponService;
|
||||
private readonly MetaService _metaService;
|
||||
private readonly InventoryService _inventoryService;
|
||||
|
|
@ -50,7 +52,7 @@ public unsafe class DebugTab : ITab
|
|||
private readonly ObjectManager _objectManager;
|
||||
private readonly GlamourerIpc _ipc;
|
||||
private readonly CodeService _code;
|
||||
private readonly ImportService _importService;
|
||||
private readonly ImportService _importService;
|
||||
|
||||
private readonly ItemManager _items;
|
||||
private readonly ActorService _actors;
|
||||
|
|
@ -82,7 +84,7 @@ public unsafe class DebugTab : ITab
|
|||
PenumbraChangedItemTooltip penumbraTooltip, MetaService metaService, GlamourerIpc ipc, DalamudPluginInterface pluginInterface,
|
||||
AutoDesignManager autoDesignManager, JobService jobs, CodeService code, CustomizeUnlockManager customizeUnlocks,
|
||||
ItemUnlockManager itemUnlocks, DesignConverter designConverter, ImportService importService, InventoryService inventoryService,
|
||||
HumanModelList humans, FunModule funModule)
|
||||
HumanModelList humans, FunModule funModule, CrestService crestService)
|
||||
{
|
||||
_changeCustomizeService = changeCustomizeService;
|
||||
_visorService = visorService;
|
||||
|
|
@ -107,10 +109,11 @@ public unsafe class DebugTab : ITab
|
|||
_customizeUnlocks = customizeUnlocks;
|
||||
_itemUnlocks = itemUnlocks;
|
||||
_designConverter = designConverter;
|
||||
_importService = importService;
|
||||
_importService = importService;
|
||||
_inventoryService = inventoryService;
|
||||
_humans = humans;
|
||||
_funModule = funModule;
|
||||
_crestService = crestService;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> Label
|
||||
|
|
@ -200,6 +203,7 @@ public unsafe class DebugTab : ITab
|
|||
DrawWetness(actor, model);
|
||||
DrawEquip(actor, model);
|
||||
DrawCustomize(actor, model);
|
||||
DrawCrests(actor, model);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#region Penumbra
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
|
|
@ -27,6 +30,7 @@ public sealed unsafe class CrestService : EventWrapper<Action<Model, EquipSlot,
|
|||
public CrestService(IGameInteropProvider interop)
|
||||
: base(nameof(CrestService))
|
||||
{
|
||||
interop.InitializeFromAttributes(this);
|
||||
_humanSetFreeCompanyCrestVisibleOnSlot =
|
||||
interop.HookFromAddress<SetCrestDelegateIntern>(_humanVTable[96], HumanSetFreeCompanyCrestVisibleOnSlotDetour);
|
||||
_weaponSetFreeCompanyCrestVisibleOnSlot =
|
||||
|
|
@ -48,10 +52,68 @@ public sealed unsafe class CrestService : EventWrapper<Action<Model, EquipSlot,
|
|||
visible = ret;
|
||||
}
|
||||
|
||||
public void UpdateCrest(Model drawObject, EquipSlot slot, bool crest)
|
||||
public static bool GetModelCrest(Actor gameObject, CrestFlag slot)
|
||||
{
|
||||
using var _ = _inUpdate.EnterMethod();
|
||||
drawObject.SetFreeCompanyCrestVisibleOnSlot(slot, crest);
|
||||
if (!gameObject.IsCharacter)
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System;
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
|
@ -106,7 +107,7 @@ public readonly unsafe struct Actor : IEquatable<Actor>
|
|||
public CharacterArmor GetArmor(EquipSlot slot)
|
||||
=> ((CharacterArmor*)&AsCharacter->DrawData.Head)[slot.ToIndex()];
|
||||
|
||||
public bool GetCrest(EquipSlot slot)
|
||||
public bool GetCrest(CrestFlag slot)
|
||||
=> (GetFreeCompanyCrestBitfield() & CrestMask(slot)) != 0;
|
||||
|
||||
public CharacterWeapon GetMainhand()
|
||||
|
|
@ -122,15 +123,15 @@ public readonly unsafe struct Actor : IEquatable<Actor>
|
|||
private byte GetFreeCompanyCrestBitfield()
|
||||
=> ((byte*)Address)[0x1BBB];
|
||||
|
||||
private static byte CrestMask(EquipSlot slot)
|
||||
private static byte CrestMask(CrestFlag slot)
|
||||
=> slot switch
|
||||
{
|
||||
EquipSlot.OffHand => 0x01,
|
||||
EquipSlot.Head => 0x02,
|
||||
EquipSlot.Body => 0x04,
|
||||
EquipSlot.Hands => 0x08,
|
||||
EquipSlot.Legs => 0x10,
|
||||
EquipSlot.Feet => 0x20,
|
||||
CrestFlag.OffHand => 0x01,
|
||||
CrestFlag.Head => 0x02,
|
||||
CrestFlag.Body => 0x04,
|
||||
CrestFlag.Hands => 0x08,
|
||||
CrestFlag.Legs => 0x10,
|
||||
CrestFlag.Feet => 0x20,
|
||||
_ => 0x00,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -91,9 +91,6 @@ public readonly unsafe struct Model : IEquatable<Model>
|
|||
public CharacterArmor GetArmor(EquipSlot slot)
|
||||
=> ((CharacterArmor*)&AsHuman->Head)[slot.ToIndex()];
|
||||
|
||||
public bool GetCrest(EquipSlot slot)
|
||||
=> IsFreeCompanyCrestVisibleOnSlot(slot);
|
||||
|
||||
public Customize GetCustomize()
|
||||
=> *(Customize*)&AsHuman->Customize;
|
||||
|
||||
|
|
@ -198,35 +195,6 @@ public readonly unsafe struct Model : IEquatable<Model>
|
|||
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()
|
||||
=> $"0x{Address:X}";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public class ActorState
|
|||
=> ref _sources[slot.ToIndex() + (stain ? EquipFlagExtensions.NumEquipFlags / 2 : 0)];
|
||||
|
||||
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]
|
||||
=> ref _sources[EquipFlagExtensions.NumEquipFlags + (int)type];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue