diff --git a/Dalamud/Game/Inventory/GameInventory.cs b/Dalamud/Game/Inventory/GameInventory.cs index 9a0388113..4dc7d7251 100644 --- a/Dalamud/Game/Inventory/GameInventory.cs +++ b/Dalamud/Game/Inventory/GameInventory.cs @@ -3,12 +3,15 @@ using System.Collections.Generic; using System.Linq; using Dalamud.Game.Inventory.InventoryEventArgTypes; +using Dalamud.Hooking; using Dalamud.IoC; using Dalamud.IoC.Internal; using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Client.UI; + namespace Dalamud.Game.Inventory; /// @@ -31,18 +34,30 @@ internal class GameInventory : IDisposable, IServiceType [ServiceManager.ServiceDependency] private readonly Framework framework = Service.Get(); + private readonly Hook raptureAtkModuleUpdateHook; + private readonly GameInventoryType[] inventoryTypes; private readonly GameInventoryItem[]?[] inventoryItems; private bool subscribersChanged; + private bool inventoriesMightBeChanged; [ServiceManager.ServiceConstructor] private GameInventory() { this.inventoryTypes = Enum.GetValues(); this.inventoryItems = new GameInventoryItem[this.inventoryTypes.Length][]; + + unsafe + { + this.raptureAtkModuleUpdateHook = Hook.FromFunctionPointerVariable( + new(&((RaptureAtkModule.RaptureAtkModuleVTable*)RaptureAtkModule.StaticAddressPointers.VTable)->Update), + this.RaptureAtkModuleUpdateDetour); + } } + private unsafe delegate void RaptureAtkModuleUpdateDelegate(RaptureAtkModule* ram, float f1); + /// public void Dispose() { @@ -52,6 +67,7 @@ internal class GameInventory : IDisposable, IServiceType this.subscribersPendingChange.Clear(); this.subscribersChanged = false; this.framework.Update -= this.OnFrameworkUpdate; + this.raptureAtkModuleUpdateHook.Dispose(); } } @@ -66,7 +82,11 @@ internal class GameInventory : IDisposable, IServiceType this.subscribersPendingChange.Add(s); this.subscribersChanged = true; if (this.subscribersPendingChange.Count == 1) + { + this.inventoriesMightBeChanged = true; this.framework.Update += this.OnFrameworkUpdate; + this.raptureAtkModuleUpdateHook.Enable(); + } } } @@ -82,12 +102,20 @@ internal class GameInventory : IDisposable, IServiceType return; this.subscribersChanged = true; if (this.subscribersPendingChange.Count == 0) + { this.framework.Update -= this.OnFrameworkUpdate; + this.raptureAtkModuleUpdateHook.Disable(); + } } } private void OnFrameworkUpdate(IFramework framework1) { + if (!this.inventoriesMightBeChanged) + return; + + this.inventoriesMightBeChanged = false; + for (var i = 0; i < this.inventoryTypes.Length; i++) { var newItems = GameInventoryItem.GetReadOnlySpanOfInventory(this.inventoryTypes[i]); @@ -287,6 +315,12 @@ internal class GameInventory : IDisposable, IServiceType this.mergedEvents.Clear(); } + private unsafe void RaptureAtkModuleUpdateDetour(RaptureAtkModule* ram, float f1) + { + this.inventoriesMightBeChanged |= ram->AgentUpdateFlag != 0; + this.raptureAtkModuleUpdateHook.Original(ram, f1); + } + /// /// A view of , so that the number of items /// contained within can be known in advance, and it can be enumerated multiple times.