diff --git a/Glamourer/Interop/InventoryService.cs b/Glamourer/Interop/InventoryService.cs index 6c4a223..f0ed6b5 100644 --- a/Glamourer/Interop/InventoryService.cs +++ b/Glamourer/Interop/InventoryService.cs @@ -13,9 +13,10 @@ namespace Glamourer.Interop; public sealed unsafe class InventoryService : IDisposable, IRequiredService { - private readonly MovedEquipment _movedItemsEvent; - private readonly EquippedGearset _gearsetEvent; + private readonly MovedEquipment _movedItemsEvent; + private readonly EquippedGearset _gearsetEvent; private readonly List<(EquipSlot, uint, StainIds)> _itemList = new(12); + public InventoryService(MovedEquipment movedItemsEvent, IGameInteropProvider interop, EquippedGearset gearsetEvent) { _movedItemsEvent = movedItemsEvent; @@ -80,18 +81,18 @@ public sealed unsafe class InventoryService : IDisposable, IRequiredService } var plate = MirageManager.Instance()->GlamourPlates[glamourPlateId - 1]; - Add(EquipSlot.MainHand, plate.ItemIds[0], StainIds.FromGlamourPlate(plate, 0), ref entry->Items[0]); - Add(EquipSlot.OffHand, plate.ItemIds[1], StainIds.FromGlamourPlate(plate, 1), ref entry->Items[1]); - Add(EquipSlot.Head, plate.ItemIds[2], StainIds.FromGlamourPlate(plate, 2), ref entry->Items[2]); - Add(EquipSlot.Body, plate.ItemIds[3], StainIds.FromGlamourPlate(plate, 3), ref entry->Items[3]); - Add(EquipSlot.Hands, plate.ItemIds[4], StainIds.FromGlamourPlate(plate, 4), ref entry->Items[5]); - Add(EquipSlot.Legs, plate.ItemIds[5], StainIds.FromGlamourPlate(plate, 5), ref entry->Items[6]); - Add(EquipSlot.Feet, plate.ItemIds[6], StainIds.FromGlamourPlate(plate, 6), ref entry->Items[7]); - Add(EquipSlot.Ears, plate.ItemIds[7], StainIds.FromGlamourPlate(plate, 7), ref entry->Items[8]); - Add(EquipSlot.Neck, plate.ItemIds[8], StainIds.FromGlamourPlate(plate, 8), ref entry->Items[9]); - Add(EquipSlot.Wrists, plate.ItemIds[9], StainIds.FromGlamourPlate(plate, 9), ref entry->Items[10]); - Add(EquipSlot.RFinger, plate.ItemIds[10], StainIds.FromGlamourPlate(plate, 10), ref entry->Items[11]); - Add(EquipSlot.LFinger, plate.ItemIds[11], StainIds.FromGlamourPlate(plate, 11), ref entry->Items[12]); + Add(EquipSlot.MainHand, plate.ItemIds[0], StainIds.FromGlamourPlate(plate, 0), ref entry->Items[0]); + Add(EquipSlot.OffHand, plate.ItemIds[1], StainIds.FromGlamourPlate(plate, 1), ref entry->Items[1]); + Add(EquipSlot.Head, plate.ItemIds[2], StainIds.FromGlamourPlate(plate, 2), ref entry->Items[2]); + Add(EquipSlot.Body, plate.ItemIds[3], StainIds.FromGlamourPlate(plate, 3), ref entry->Items[3]); + Add(EquipSlot.Hands, plate.ItemIds[4], StainIds.FromGlamourPlate(plate, 4), ref entry->Items[5]); + Add(EquipSlot.Legs, plate.ItemIds[5], StainIds.FromGlamourPlate(plate, 5), ref entry->Items[6]); + Add(EquipSlot.Feet, plate.ItemIds[6], StainIds.FromGlamourPlate(plate, 6), ref entry->Items[7]); + Add(EquipSlot.Ears, plate.ItemIds[7], StainIds.FromGlamourPlate(plate, 7), ref entry->Items[8]); + Add(EquipSlot.Neck, plate.ItemIds[8], StainIds.FromGlamourPlate(plate, 8), ref entry->Items[9]); + Add(EquipSlot.Wrists, plate.ItemIds[9], StainIds.FromGlamourPlate(plate, 9), ref entry->Items[10]); + Add(EquipSlot.RFinger, plate.ItemIds[10], StainIds.FromGlamourPlate(plate, 10), ref entry->Items[11]); + Add(EquipSlot.LFinger, plate.ItemIds[11], StainIds.FromGlamourPlate(plate, 11), ref entry->Items[12]); } else { @@ -106,17 +107,17 @@ public sealed unsafe class InventoryService : IDisposable, IRequiredService } Add(EquipSlot.MainHand, ref entry->Items[0]); - Add(EquipSlot.OffHand, ref entry->Items[1]); - Add(EquipSlot.Head, ref entry->Items[2]); - Add(EquipSlot.Body, ref entry->Items[3]); - Add(EquipSlot.Hands, ref entry->Items[5]); - Add(EquipSlot.Legs, ref entry->Items[6]); - Add(EquipSlot.Feet, ref entry->Items[7]); - Add(EquipSlot.Ears, ref entry->Items[8]); - Add(EquipSlot.Neck, ref entry->Items[9]); - Add(EquipSlot.Wrists, ref entry->Items[10]); - Add(EquipSlot.RFinger, ref entry->Items[11]); - Add(EquipSlot.LFinger, ref entry->Items[12]); + Add(EquipSlot.OffHand, ref entry->Items[1]); + Add(EquipSlot.Head, ref entry->Items[2]); + Add(EquipSlot.Body, ref entry->Items[3]); + Add(EquipSlot.Hands, ref entry->Items[5]); + Add(EquipSlot.Legs, ref entry->Items[6]); + Add(EquipSlot.Feet, ref entry->Items[7]); + Add(EquipSlot.Ears, ref entry->Items[8]); + Add(EquipSlot.Neck, ref entry->Items[9]); + Add(EquipSlot.Wrists, ref entry->Items[10]); + Add(EquipSlot.RFinger, ref entry->Items[11]); + Add(EquipSlot.LFinger, ref entry->Items[12]); } _movedItemsEvent.Invoke(_itemList.ToArray()); @@ -203,18 +204,18 @@ public sealed unsafe class InventoryService : IDisposable, IRequiredService private static EquipSlot GetSlot(uint slot) => slot switch { - 0 => EquipSlot.MainHand, - 1 => EquipSlot.OffHand, - 2 => EquipSlot.Head, - 3 => EquipSlot.Body, - 4 => EquipSlot.Hands, - 6 => EquipSlot.Legs, - 7 => EquipSlot.Feet, - 8 => EquipSlot.Ears, - 9 => EquipSlot.Neck, + 0 => EquipSlot.MainHand, + 1 => EquipSlot.OffHand, + 2 => EquipSlot.Head, + 3 => EquipSlot.Body, + 4 => EquipSlot.Hands, + 6 => EquipSlot.Legs, + 7 => EquipSlot.Feet, + 8 => EquipSlot.Ears, + 9 => EquipSlot.Neck, 10 => EquipSlot.Wrists, 11 => EquipSlot.RFinger, 12 => EquipSlot.LFinger, - _ => EquipSlot.Unknown, + _ => EquipSlot.Unknown, }; } diff --git a/Glamourer/Interop/UpdateSlotService.cs b/Glamourer/Interop/UpdateSlotService.cs index 5f6e9cb..e453c6e 100644 --- a/Glamourer/Interop/UpdateSlotService.cs +++ b/Glamourer/Interop/UpdateSlotService.cs @@ -11,46 +11,6 @@ using Penumbra.GameData.Structs; namespace Glamourer.Interop; -// Can be removed once merged with client structs and referenced directly. See: https://github.com/aers/FFXIVClientStructs/pull/1277/files -[StructLayout(LayoutKind.Explicit)] -public readonly struct GearsetDataStruct -{ - // Stores the weapon data. Includes both dyes in the data. - [FieldOffset(0)] public readonly WeaponModelId MainhandWeaponData; - [FieldOffset(8)] public readonly WeaponModelId OffhandWeaponData; - - [FieldOffset(16)] public readonly byte CrestBitField; // A Bitfield:: ShieldCrest == 1, HeadCrest == 2, Chest Crest == 4 - [FieldOffset(17)] public readonly byte JobId; // Job ID associated with the gearset change. - - // Flicks from 0 to 127 (anywhere inbetween), have yet to associate what it is linked to. Remains the same when flicking between gearsets of the same job. - [FieldOffset(18)] public readonly byte UNK_18; - [FieldOffset(19)] public readonly byte UNK_19; // I have never seen this be anything other than 0. - - // Legacy helmet equip slot armor for a character. - [FieldOffset(20)] public readonly LegacyCharacterArmor HeadSlotArmor; - [FieldOffset(24)] public readonly LegacyCharacterArmor TopSlotArmor; - [FieldOffset(28)] public readonly LegacyCharacterArmor ArmsSlotArmor; - [FieldOffset(32)] public readonly LegacyCharacterArmor LegsSlotArmor; - [FieldOffset(26)] public readonly LegacyCharacterArmor FeetSlotArmor; - [FieldOffset(40)] public readonly LegacyCharacterArmor EarSlotArmor; - [FieldOffset(44)] public readonly LegacyCharacterArmor NeckSlotArmor; - [FieldOffset(48)] public readonly LegacyCharacterArmor WristSlotArmor; - [FieldOffset(52)] public readonly LegacyCharacterArmor RFingerSlotArmor; - [FieldOffset(56)] public readonly LegacyCharacterArmor LFingerSlotArmor; - - // Byte array of all slot's secondary dyes. - [FieldOffset(60)] public readonly byte HeadSlotSecondaryDye; - [FieldOffset(61)] public readonly byte TopSlotSecondaryDye; - [FieldOffset(62)] public readonly byte ArmsSlotSecondaryDye; - [FieldOffset(63)] public readonly byte LegsSlotSecondaryDye; - [FieldOffset(64)] public readonly byte FeetSlotSecondaryDye; - [FieldOffset(65)] public readonly byte EarSlotSecondaryDye; - [FieldOffset(66)] public readonly byte NeckSlotSecondaryDye; - [FieldOffset(67)] public readonly byte WristSlotSecondaryDye; - [FieldOffset(68)] public readonly byte RFingerSlotSecondaryDye; - [FieldOffset(69)] public readonly byte LFingerSlotSecondaryDye; -} - public unsafe class UpdateSlotService : IDisposable { public readonly EquipSlotUpdating EquipSlotUpdatingEvent; @@ -145,22 +105,20 @@ public unsafe class UpdateSlotService : IDisposable private ulong FlagSlotForUpdateDetour(nint drawObject, uint slotIdx, CharacterArmor* data) { - var slot = slotIdx.ToEquipSlot(); + var slot = slotIdx.ToEquipSlot(); var returnValue = ulong.MaxValue; EquipSlotUpdatingEvent.Invoke(drawObject, slot, ref *data, ref returnValue); Glamourer.Log.Excessive($"[FlagSlotForUpdate] Called with 0x{drawObject:X} for slot {slot} with {*data} ({returnValue:X})."); - returnValue = returnValue == ulong.MaxValue ? _flagSlotForUpdateHook.Original(drawObject, slotIdx, data) : returnValue; - return returnValue; + return returnValue == ulong.MaxValue ? _flagSlotForUpdateHook.Original(drawObject, slotIdx, data) : returnValue; } private ulong FlagBonusSlotForUpdateDetour(nint drawObject, uint slotIdx, CharacterArmor* data) { - var slot = slotIdx.ToBonusSlot(); + var slot = slotIdx.ToBonusSlot(); var returnValue = ulong.MaxValue; BonusSlotUpdatingEvent.Invoke(drawObject, slot, ref *data, ref returnValue); Glamourer.Log.Excessive($"[FlagBonusSlotForUpdate] Called with 0x{drawObject:X} for slot {slot} with {*data} ({returnValue:X})."); - returnValue = returnValue == ulong.MaxValue ? _flagBonusSlotForUpdateHook.Original(drawObject, slotIdx, data) : returnValue; - return returnValue; + return returnValue == ulong.MaxValue ? _flagBonusSlotForUpdateHook.Original(drawObject, slotIdx, data) : returnValue; } private ulong FlagSlotForUpdateInterop(Model drawObject, EquipSlot slot, CharacterArmor armor) @@ -175,7 +133,6 @@ public unsafe class UpdateSlotService : IDisposable Model drawObject = drawDataContainer->OwnerObject->DrawObject; Glamourer.Log.Verbose($"[LoadAllEquipmentDetour] Owner: 0x{drawObject.Address:X} Finished Applying its GameState!"); GearsetDataLoadedEvent.Invoke(drawObject); - // Can use for debugging, if desired. // Glamourer.Log.Verbose($"[LoadAllEquipmentDetour] GearsetItemData: {FormatGearsetItemDataStruct(*gearsetData)}"); return ret; } @@ -199,3 +156,43 @@ public unsafe class UpdateSlotService : IDisposable return ret; } } + +// Can be removed once merged with client structs and referenced directly. See: https://github.com/aers/FFXIVClientStructs/pull/1277/files +[StructLayout(LayoutKind.Explicit)] +public readonly struct GearsetDataStruct +{ + // Stores the weapon data. Includes both dyes in the data. + [FieldOffset(0)] public readonly WeaponModelId MainhandWeaponData; + [FieldOffset(8)] public readonly WeaponModelId OffhandWeaponData; + + [FieldOffset(16)] public readonly byte CrestBitField; // A Bitfield:: ShieldCrest == 1, HeadCrest == 2, Chest Crest == 4 + [FieldOffset(17)] public readonly byte JobId; // Job ID associated with the gearset change. + + // Flicks from 0 to 127 (anywhere inbetween), have yet to associate what it is linked to. Remains the same when flicking between gearsets of the same job. + [FieldOffset(18)] public readonly byte UNK_18; + [FieldOffset(19)] public readonly byte UNK_19; // I have never seen this be anything other than 0. + + // Legacy helmet equip slot armor for a character. + [FieldOffset(20)] public readonly LegacyCharacterArmor HeadSlotArmor; + [FieldOffset(24)] public readonly LegacyCharacterArmor TopSlotArmor; + [FieldOffset(28)] public readonly LegacyCharacterArmor ArmsSlotArmor; + [FieldOffset(32)] public readonly LegacyCharacterArmor LegsSlotArmor; + [FieldOffset(26)] public readonly LegacyCharacterArmor FeetSlotArmor; + [FieldOffset(40)] public readonly LegacyCharacterArmor EarSlotArmor; + [FieldOffset(44)] public readonly LegacyCharacterArmor NeckSlotArmor; + [FieldOffset(48)] public readonly LegacyCharacterArmor WristSlotArmor; + [FieldOffset(52)] public readonly LegacyCharacterArmor RFingerSlotArmor; + [FieldOffset(56)] public readonly LegacyCharacterArmor LFingerSlotArmor; + + // Byte array of all slot's secondary dyes. + [FieldOffset(60)] public readonly byte HeadSlotSecondaryDye; + [FieldOffset(61)] public readonly byte TopSlotSecondaryDye; + [FieldOffset(62)] public readonly byte ArmsSlotSecondaryDye; + [FieldOffset(63)] public readonly byte LegsSlotSecondaryDye; + [FieldOffset(64)] public readonly byte FeetSlotSecondaryDye; + [FieldOffset(65)] public readonly byte EarSlotSecondaryDye; + [FieldOffset(66)] public readonly byte NeckSlotSecondaryDye; + [FieldOffset(67)] public readonly byte WristSlotSecondaryDye; + [FieldOffset(68)] public readonly byte RFingerSlotSecondaryDye; + [FieldOffset(69)] public readonly byte LFingerSlotSecondaryDye; +} diff --git a/Glamourer/State/StateEditor.cs b/Glamourer/State/StateEditor.cs index 891c61d..b122352 100644 --- a/Glamourer/State/StateEditor.cs +++ b/Glamourer/State/StateEditor.cs @@ -253,7 +253,7 @@ public class StateEditor( return; var actors = Applier.ChangeMetaState(state, index, settings.Source.RequiresChange()); - Glamourer.Log.Debug( + Glamourer.Log.Verbose( $"Set {index.ToName()} in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]"); StateChanged.Invoke(StateChangeType.Other, settings.Source, state, actors, new MetaTransaction(index, old, value)); } @@ -417,7 +417,8 @@ public class StateEditor( ? Applier.ApplyAll(state, requiresRedraw, false) : ActorData.Invalid; - Glamourer.Log.Verbose($"Applied design to {state.Identifier.Incognito(null)}. [Affecting {actors.ToLazyString("nothing")}.]"); + Glamourer.Log.Verbose( + $"Applied design to {state.Identifier.Incognito(null)}. [Affecting {actors.ToLazyString("nothing")}.]"); StateChanged.Invoke(StateChangeType.Design, state.Sources[MetaIndex.Wetness], state, actors, null); // FIXME: maybe later if(settings.SendStateUpdate) StateUpdated.Invoke(StateUpdateType.DesignApplied, actors);