mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-26 02:19:18 +01:00
Enable tracking only when there exists a subscriber
This commit is contained in:
parent
5f0b65a6c4
commit
e594d59986
12 changed files with 381 additions and 234 deletions
|
|
@ -2,15 +2,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
using Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Dalamud.Game.Inventory;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -18,9 +16,10 @@ namespace Dalamud.Game.Inventory;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal class GameInventory : IDisposable, IServiceType, IGameInventory
|
||||
internal class GameInventory : IDisposable, IServiceType
|
||||
{
|
||||
private static readonly ModuleLog Log = new(nameof(GameInventory));
|
||||
private readonly List<GameInventoryPluginScoped> subscribersPendingChange = new();
|
||||
private readonly List<GameInventoryPluginScoped> subscribers = new();
|
||||
|
||||
private readonly List<InventoryItemAddedArgs> addedEvents = new();
|
||||
private readonly List<InventoryItemRemovedArgs> removedEvents = new();
|
||||
|
|
@ -32,120 +31,58 @@ internal class GameInventory : IDisposable, IServiceType, IGameInventory
|
|||
[ServiceManager.ServiceDependency]
|
||||
private readonly Framework framework = Service<Framework>.Get();
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly DalamudConfiguration dalamudConfiguration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
private readonly GameInventoryType[] inventoryTypes;
|
||||
private readonly GameInventoryItem[]?[] inventoryItems;
|
||||
|
||||
private bool subscribersChanged;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private GameInventory()
|
||||
{
|
||||
this.inventoryTypes = Enum.GetValues<GameInventoryType>();
|
||||
this.inventoryItems = new GameInventoryItem[this.inventoryTypes.Length][];
|
||||
|
||||
this.framework.Update += this.OnFrameworkUpdate;
|
||||
|
||||
// Separate log logic as an event handler.
|
||||
this.InventoryChanged += events =>
|
||||
{
|
||||
if (this.dalamudConfiguration.LogLevel > LogEventLevel.Verbose)
|
||||
return;
|
||||
|
||||
foreach (var e in events)
|
||||
{
|
||||
if (e is InventoryComplexEventArgs icea)
|
||||
Log.Verbose($"{icea}\n\t├ {icea.SourceEvent}\n\t└ {icea.TargetEvent}");
|
||||
else
|
||||
Log.Verbose($"{e}");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangelogDelegate? InventoryChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangelogDelegate? InventoryChangedRaw;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate? ItemAdded;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate? ItemRemoved;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate? ItemChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate? ItemMoved;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate? ItemSplit;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate? ItemMerged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate<InventoryItemAddedArgs>? ItemAddedExplicit;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate<InventoryItemRemovedArgs>? ItemRemovedExplicit;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate<InventoryItemChangedArgs>? ItemChangedExplicit;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate<InventoryItemMovedArgs>? ItemMovedExplicit;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate<InventoryItemSplitArgs>? ItemSplitExplicit;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangedDelegate<InventoryItemMergedArgs>? ItemMergedExplicit;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
lock (this.subscribersPendingChange)
|
||||
{
|
||||
this.subscribers.Clear();
|
||||
this.subscribersPendingChange.Clear();
|
||||
this.subscribersChanged = false;
|
||||
this.framework.Update -= this.OnFrameworkUpdate;
|
||||
}
|
||||
|
||||
private static void InvokeSafely(
|
||||
IGameInventory.InventoryChangelogDelegate? cb,
|
||||
IReadOnlyCollection<InventoryEventArgs> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
cb?.Invoke(data);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
/// <summary>
|
||||
/// Subscribe to events.
|
||||
/// </summary>
|
||||
/// <param name="s">The event target.</param>
|
||||
public void Subscribe(GameInventoryPluginScoped s)
|
||||
{
|
||||
Log.Error(e, "Exception during batch callback");
|
||||
lock (this.subscribersPendingChange)
|
||||
{
|
||||
this.subscribersPendingChange.Add(s);
|
||||
this.subscribersChanged = true;
|
||||
if (this.subscribersPendingChange.Count == 1)
|
||||
this.framework.Update += this.OnFrameworkUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
private static void InvokeSafely(IGameInventory.InventoryChangedDelegate? cb, InventoryEventArgs arg)
|
||||
/// <summary>
|
||||
/// Unsubscribe from events.
|
||||
/// </summary>
|
||||
/// <param name="s">The event target.</param>
|
||||
public void Unsubscribe(GameInventoryPluginScoped s)
|
||||
{
|
||||
try
|
||||
lock (this.subscribersPendingChange)
|
||||
{
|
||||
cb?.Invoke(arg.Type, arg);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Exception during {argType} callback", arg.Type);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InvokeSafely<T>(IGameInventory.InventoryChangedDelegate<T>? cb, T arg)
|
||||
where T : InventoryEventArgs
|
||||
{
|
||||
try
|
||||
{
|
||||
cb?.Invoke(arg);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Exception during {argType} callback", arg.Type);
|
||||
if (!this.subscribersPendingChange.Remove(s))
|
||||
return;
|
||||
this.subscribersChanged = true;
|
||||
if (this.subscribersPendingChange.Count == 0)
|
||||
this.framework.Update -= this.OnFrameworkUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,18 +130,40 @@ internal class GameInventory : IDisposable, IServiceType, IGameInventory
|
|||
if (this.addedEvents.Count == 0 && this.removedEvents.Count == 0 && this.changedEvents.Count == 0)
|
||||
return;
|
||||
|
||||
// Make a copy of subscribers, to accommodate self removal during the loop.
|
||||
if (this.subscribersChanged)
|
||||
{
|
||||
bool isNew;
|
||||
lock (this.subscribersPendingChange)
|
||||
{
|
||||
isNew = this.subscribersPendingChange.Any() && !this.subscribers.Any();
|
||||
this.subscribers.Clear();
|
||||
this.subscribers.AddRange(this.subscribersPendingChange);
|
||||
this.subscribersChanged = false;
|
||||
}
|
||||
|
||||
// Is this the first time (resuming) scanning for changes? Then discard the "changes".
|
||||
if (isNew)
|
||||
{
|
||||
this.addedEvents.Clear();
|
||||
this.removedEvents.Clear();
|
||||
this.changedEvents.Clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Broadcast InventoryChangedRaw.
|
||||
// Same reason with the above on why are there 3 lists of events involved.
|
||||
InvokeSafely(
|
||||
this.InventoryChangedRaw,
|
||||
new DeferredReadOnlyCollection<InventoryEventArgs>(
|
||||
var allRawEventsCollection = new DeferredReadOnlyCollection<InventoryEventArgs>(
|
||||
this.addedEvents.Count +
|
||||
this.removedEvents.Count +
|
||||
this.changedEvents.Count,
|
||||
() => Array.Empty<InventoryEventArgs>()
|
||||
.Concat(this.addedEvents)
|
||||
.Concat(this.removedEvents)
|
||||
.Concat(this.changedEvents)));
|
||||
.Concat(this.changedEvents));
|
||||
foreach (var s in this.subscribers)
|
||||
s.InvokeChangedRaw(allRawEventsCollection);
|
||||
|
||||
// Resolve moved items, from 1 added + 1 removed event.
|
||||
for (var iAdded = this.addedEvents.Count - 1; iAdded >= 0; --iAdded)
|
||||
|
|
@ -291,10 +250,8 @@ internal class GameInventory : IDisposable, IServiceType, IGameInventory
|
|||
}
|
||||
}
|
||||
|
||||
// Broadcast the rest.
|
||||
InvokeSafely(
|
||||
this.InventoryChanged,
|
||||
new DeferredReadOnlyCollection<InventoryEventArgs>(
|
||||
// Create a collection view of all events.
|
||||
var allEventsCollection = new DeferredReadOnlyCollection<InventoryEventArgs>(
|
||||
this.addedEvents.Count +
|
||||
this.removedEvents.Count +
|
||||
this.changedEvents.Count +
|
||||
|
|
@ -307,42 +264,18 @@ internal class GameInventory : IDisposable, IServiceType, IGameInventory
|
|||
.Concat(this.changedEvents)
|
||||
.Concat(this.movedEvents)
|
||||
.Concat(this.splitEvents)
|
||||
.Concat(this.mergedEvents)));
|
||||
.Concat(this.mergedEvents));
|
||||
|
||||
foreach (var x in this.addedEvents)
|
||||
// Broadcast the rest.
|
||||
foreach (var s in this.subscribers)
|
||||
{
|
||||
InvokeSafely(this.ItemAdded, x);
|
||||
InvokeSafely(this.ItemAddedExplicit, x);
|
||||
}
|
||||
|
||||
foreach (var x in this.removedEvents)
|
||||
{
|
||||
InvokeSafely(this.ItemRemoved, x);
|
||||
InvokeSafely(this.ItemRemovedExplicit, x);
|
||||
}
|
||||
|
||||
foreach (var x in this.changedEvents)
|
||||
{
|
||||
InvokeSafely(this.ItemChanged, x);
|
||||
InvokeSafely(this.ItemChangedExplicit, x);
|
||||
}
|
||||
|
||||
foreach (var x in this.movedEvents)
|
||||
{
|
||||
InvokeSafely(this.ItemMoved, x);
|
||||
InvokeSafely(this.ItemMovedExplicit, x);
|
||||
}
|
||||
|
||||
foreach (var x in this.splitEvents)
|
||||
{
|
||||
InvokeSafely(this.ItemSplit, x);
|
||||
InvokeSafely(this.ItemSplitExplicit, x);
|
||||
}
|
||||
|
||||
foreach (var x in this.mergedEvents)
|
||||
{
|
||||
InvokeSafely(this.ItemMerged, x);
|
||||
InvokeSafely(this.ItemMergedExplicit, x);
|
||||
s.InvokeChanged(allEventsCollection);
|
||||
s.Invoke(this.addedEvents);
|
||||
s.Invoke(this.removedEvents);
|
||||
s.Invoke(this.changedEvents);
|
||||
s.Invoke(this.movedEvents);
|
||||
s.Invoke(this.splitEvents);
|
||||
s.Invoke(this.mergedEvents);
|
||||
}
|
||||
|
||||
// We're done using the lists. Clean them up.
|
||||
|
|
@ -388,29 +321,15 @@ internal class GameInventory : IDisposable, IServiceType, IGameInventory
|
|||
#pragma warning restore SA1015
|
||||
internal class GameInventoryPluginScoped : IDisposable, IServiceType, IGameInventory
|
||||
{
|
||||
private static readonly ModuleLog Log = new(nameof(GameInventoryPluginScoped));
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly GameInventory gameInventoryService = Service<GameInventory>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameInventoryPluginScoped"/> class.
|
||||
/// </summary>
|
||||
public GameInventoryPluginScoped()
|
||||
{
|
||||
this.gameInventoryService.InventoryChanged += this.OnInventoryChangedForward;
|
||||
this.gameInventoryService.InventoryChangedRaw += this.OnInventoryChangedRawForward;
|
||||
this.gameInventoryService.ItemAdded += this.OnInventoryItemAddedForward;
|
||||
this.gameInventoryService.ItemRemoved += this.OnInventoryItemRemovedForward;
|
||||
this.gameInventoryService.ItemMoved += this.OnInventoryItemMovedForward;
|
||||
this.gameInventoryService.ItemChanged += this.OnInventoryItemChangedForward;
|
||||
this.gameInventoryService.ItemSplit += this.OnInventoryItemSplitForward;
|
||||
this.gameInventoryService.ItemMerged += this.OnInventoryItemMergedForward;
|
||||
this.gameInventoryService.ItemAddedExplicit += this.OnInventoryItemAddedExplicitForward;
|
||||
this.gameInventoryService.ItemRemovedExplicit += this.OnInventoryItemRemovedExplicitForward;
|
||||
this.gameInventoryService.ItemChangedExplicit += this.OnInventoryItemChangedExplicitForward;
|
||||
this.gameInventoryService.ItemMovedExplicit += this.OnInventoryItemMovedExplicitForward;
|
||||
this.gameInventoryService.ItemSplitExplicit += this.OnInventoryItemSplitExplicitForward;
|
||||
this.gameInventoryService.ItemMergedExplicit += this.OnInventoryItemMergedExplicitForward;
|
||||
}
|
||||
public GameInventoryPluginScoped() => this.gameInventoryService.Subscribe(this);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameInventory.InventoryChangelogDelegate? InventoryChanged;
|
||||
|
|
@ -457,20 +376,7 @@ internal class GameInventoryPluginScoped : IDisposable, IServiceType, IGameInven
|
|||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.gameInventoryService.InventoryChanged -= this.OnInventoryChangedForward;
|
||||
this.gameInventoryService.InventoryChangedRaw -= this.OnInventoryChangedRawForward;
|
||||
this.gameInventoryService.ItemAdded -= this.OnInventoryItemAddedForward;
|
||||
this.gameInventoryService.ItemRemoved -= this.OnInventoryItemRemovedForward;
|
||||
this.gameInventoryService.ItemChanged -= this.OnInventoryItemChangedForward;
|
||||
this.gameInventoryService.ItemMoved -= this.OnInventoryItemMovedForward;
|
||||
this.gameInventoryService.ItemSplit -= this.OnInventoryItemSplitForward;
|
||||
this.gameInventoryService.ItemMerged -= this.OnInventoryItemMergedForward;
|
||||
this.gameInventoryService.ItemAddedExplicit -= this.OnInventoryItemAddedExplicitForward;
|
||||
this.gameInventoryService.ItemRemovedExplicit -= this.OnInventoryItemRemovedExplicitForward;
|
||||
this.gameInventoryService.ItemChangedExplicit -= this.OnInventoryItemChangedExplicitForward;
|
||||
this.gameInventoryService.ItemMovedExplicit -= this.OnInventoryItemMovedExplicitForward;
|
||||
this.gameInventoryService.ItemSplitExplicit -= this.OnInventoryItemSplitExplicitForward;
|
||||
this.gameInventoryService.ItemMergedExplicit -= this.OnInventoryItemMergedExplicitForward;
|
||||
this.gameInventoryService.Unsubscribe(this);
|
||||
|
||||
this.InventoryChanged = null;
|
||||
this.InventoryChangedRaw = null;
|
||||
|
|
@ -488,45 +394,122 @@ internal class GameInventoryPluginScoped : IDisposable, IServiceType, IGameInven
|
|||
this.ItemMergedExplicit = null;
|
||||
}
|
||||
|
||||
private void OnInventoryChangedForward(IReadOnlyCollection<InventoryEventArgs> events)
|
||||
=> this.InventoryChanged?.Invoke(events);
|
||||
/// <summary>
|
||||
/// Invoke <see cref="InventoryChanged"/>.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
internal void InvokeChanged(IReadOnlyCollection<InventoryEventArgs> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.InventoryChanged?.Invoke(data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(
|
||||
e,
|
||||
"[{plugin}] Exception during {argType} callback",
|
||||
Service<PluginManager>.GetNullable()?.FindCallingPlugin(new(e))?.Name ?? "(unknown plugin)",
|
||||
nameof(this.InventoryChanged));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInventoryChangedRawForward(IReadOnlyCollection<InventoryEventArgs> events)
|
||||
=> this.InventoryChangedRaw?.Invoke(events);
|
||||
/// <summary>
|
||||
/// Invoke <see cref="InventoryChangedRaw"/>.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
internal void InvokeChangedRaw(IReadOnlyCollection<InventoryEventArgs> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.InventoryChangedRaw?.Invoke(data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(
|
||||
e,
|
||||
"[{plugin}] Exception during {argType} callback",
|
||||
Service<PluginManager>.GetNullable()?.FindCallingPlugin(new(e))?.Name ?? "(unknown plugin)",
|
||||
nameof(this.InventoryChangedRaw));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInventoryItemAddedForward(GameInventoryEvent type, InventoryEventArgs data)
|
||||
=> this.ItemAdded?.Invoke(type, data);
|
||||
// Note below: using List<T> instead of IEnumerable<T>, since List<T> has a specialized lightweight enumerator.
|
||||
|
||||
private void OnInventoryItemRemovedForward(GameInventoryEvent type, InventoryEventArgs data)
|
||||
=> this.ItemRemoved?.Invoke(type, data);
|
||||
/// <summary>
|
||||
/// Invoke the appropriate event handler.
|
||||
/// </summary>
|
||||
/// <param name="events">The data.</param>
|
||||
internal void Invoke(List<InventoryItemAddedArgs> events) =>
|
||||
Invoke(this.ItemAdded, this.ItemAddedExplicit, events);
|
||||
|
||||
private void OnInventoryItemChangedForward(GameInventoryEvent type, InventoryEventArgs data)
|
||||
=> this.ItemChanged?.Invoke(type, data);
|
||||
/// <summary>
|
||||
/// Invoke the appropriate event handler.
|
||||
/// </summary>
|
||||
/// <param name="events">The data.</param>
|
||||
internal void Invoke(List<InventoryItemRemovedArgs> events) =>
|
||||
Invoke(this.ItemRemoved, this.ItemRemovedExplicit, events);
|
||||
|
||||
private void OnInventoryItemMovedForward(GameInventoryEvent type, InventoryEventArgs data)
|
||||
=> this.ItemMoved?.Invoke(type, data);
|
||||
/// <summary>
|
||||
/// Invoke the appropriate event handler.
|
||||
/// </summary>
|
||||
/// <param name="events">The data.</param>
|
||||
internal void Invoke(List<InventoryItemChangedArgs> events) =>
|
||||
Invoke(this.ItemChanged, this.ItemChangedExplicit, events);
|
||||
|
||||
private void OnInventoryItemSplitForward(GameInventoryEvent type, InventoryEventArgs data)
|
||||
=> this.ItemSplit?.Invoke(type, data);
|
||||
/// <summary>
|
||||
/// Invoke the appropriate event handler.
|
||||
/// </summary>
|
||||
/// <param name="events">The data.</param>
|
||||
internal void Invoke(List<InventoryItemMovedArgs> events) =>
|
||||
Invoke(this.ItemMoved, this.ItemMovedExplicit, events);
|
||||
|
||||
private void OnInventoryItemMergedForward(GameInventoryEvent type, InventoryEventArgs data)
|
||||
=> this.ItemMerged?.Invoke(type, data);
|
||||
/// <summary>
|
||||
/// Invoke the appropriate event handler.
|
||||
/// </summary>
|
||||
/// <param name="events">The data.</param>
|
||||
internal void Invoke(List<InventoryItemSplitArgs> events) =>
|
||||
Invoke(this.ItemSplit, this.ItemSplitExplicit, events);
|
||||
|
||||
private void OnInventoryItemAddedExplicitForward(InventoryItemAddedArgs data)
|
||||
=> this.ItemAddedExplicit?.Invoke(data);
|
||||
/// <summary>
|
||||
/// Invoke the appropriate event handler.
|
||||
/// </summary>
|
||||
/// <param name="events">The data.</param>
|
||||
internal void Invoke(List<InventoryItemMergedArgs> events) =>
|
||||
Invoke(this.ItemMerged, this.ItemMergedExplicit, events);
|
||||
|
||||
private void OnInventoryItemRemovedExplicitForward(InventoryItemRemovedArgs data)
|
||||
=> this.ItemRemovedExplicit?.Invoke(data);
|
||||
private static void Invoke<T>(
|
||||
IGameInventory.InventoryChangedDelegate? cb,
|
||||
IGameInventory.InventoryChangedDelegate<T>? cbt,
|
||||
List<T> events) where T : InventoryEventArgs
|
||||
{
|
||||
foreach (var evt in events)
|
||||
{
|
||||
try
|
||||
{
|
||||
cb?.Invoke(evt.Type, evt);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(
|
||||
e,
|
||||
"[{plugin}] Exception during untyped callback for {evt}",
|
||||
Service<PluginManager>.GetNullable()?.FindCallingPlugin(new(e))?.Name ?? "(unknown plugin)",
|
||||
evt);
|
||||
}
|
||||
|
||||
private void OnInventoryItemChangedExplicitForward(InventoryItemChangedArgs data)
|
||||
=> this.ItemChangedExplicit?.Invoke(data);
|
||||
|
||||
private void OnInventoryItemMovedExplicitForward(InventoryItemMovedArgs data)
|
||||
=> this.ItemMovedExplicit?.Invoke(data);
|
||||
|
||||
private void OnInventoryItemSplitExplicitForward(InventoryItemSplitArgs data)
|
||||
=> this.ItemSplitExplicit?.Invoke(data);
|
||||
|
||||
private void OnInventoryItemMergedExplicitForward(InventoryItemMergedArgs data)
|
||||
=> this.ItemMergedExplicit?.Invoke(data);
|
||||
try
|
||||
{
|
||||
cbt?.Invoke(evt);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(
|
||||
e,
|
||||
"[{plugin}] Exception during typed callback for {evt}",
|
||||
Service<PluginManager>.GetNullable()?.FindCallingPlugin(new(e))?.Name ?? "(unknown plugin)",
|
||||
evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the data associated with an item being affected across different slots, possibly in different containers.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract base class representing inventory changed events.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the data associated with an item being added to an inventory.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the data associated with an items properties being changed.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the data associated with an item being merged from two stacks into one.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the data associated with an item being moved from one inventory and added to another.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the data associated with an item being removed from an inventory.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the data associated with an item being split from one stack into two.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ internal class DataWindow : Window
|
|||
new FateTableWidget(),
|
||||
new FlyTextWidget(),
|
||||
new FontAwesomeTestWidget(),
|
||||
new GameInventoryTestWidget(),
|
||||
new GamepadWidget(),
|
||||
new GaugeWidget(),
|
||||
new HookWidget(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,163 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Game.Inventory;
|
||||
using Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Dalamud.Logging.Internal;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Tester for <see cref="GameInventory"/>.
|
||||
/// </summary>
|
||||
internal class GameInventoryTestWidget : IDataWindowWidget
|
||||
{
|
||||
private static readonly ModuleLog Log = new(nameof(GameInventoryTestWidget));
|
||||
|
||||
private GameInventoryPluginScoped? scoped;
|
||||
private bool standardEnabled;
|
||||
private bool rawEnabled;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string[]? CommandShortcuts { get; init; } = { "gameinventorytest" };
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string DisplayName { get; init; } = "GameInventory Test";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Ready { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Load() => this.Ready = true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Draw()
|
||||
{
|
||||
if (Service<DalamudConfiguration>.Get().LogLevel > LogEventLevel.Information)
|
||||
{
|
||||
ImGuiHelpers.SafeTextColoredWrapped(
|
||||
ImGuiColors.DalamudRed,
|
||||
"Enable LogLevel=Information display to see the logs.");
|
||||
}
|
||||
|
||||
using var table = ImRaii.Table(this.DisplayName, 3, ImGuiTableFlags.SizingFixedFit);
|
||||
if (!table.Success)
|
||||
return;
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted("Standard Logging");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.Disabled(this.standardEnabled))
|
||||
{
|
||||
if (ImGui.Button("Enable##standard-enable") && !this.standardEnabled)
|
||||
{
|
||||
this.scoped ??= new();
|
||||
this.scoped.InventoryChanged += ScopedOnInventoryChanged;
|
||||
this.standardEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.Disabled(!this.standardEnabled))
|
||||
{
|
||||
if (ImGui.Button("Disable##standard-disable") && this.scoped is not null && this.standardEnabled)
|
||||
{
|
||||
this.scoped.InventoryChanged -= ScopedOnInventoryChanged;
|
||||
this.standardEnabled = false;
|
||||
if (!this.rawEnabled)
|
||||
{
|
||||
this.scoped.Dispose();
|
||||
this.scoped = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.TableNextRow();
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted("Raw Logging");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.Disabled(this.rawEnabled))
|
||||
{
|
||||
if (ImGui.Button("Enable##raw-enable") && !this.rawEnabled)
|
||||
{
|
||||
this.scoped ??= new();
|
||||
this.scoped.InventoryChangedRaw += ScopedOnInventoryChangedRaw;
|
||||
this.rawEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.Disabled(!this.rawEnabled))
|
||||
{
|
||||
if (ImGui.Button("Disable##raw-disable") && this.scoped is not null && this.rawEnabled)
|
||||
{
|
||||
this.scoped.InventoryChangedRaw -= ScopedOnInventoryChangedRaw;
|
||||
this.rawEnabled = false;
|
||||
if (!this.standardEnabled)
|
||||
{
|
||||
this.scoped.Dispose();
|
||||
this.scoped = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.TableNextRow();
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted("All");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.Disabled(this.standardEnabled && this.rawEnabled))
|
||||
{
|
||||
if (ImGui.Button("Enable##all-enable"))
|
||||
{
|
||||
this.scoped ??= new();
|
||||
if (!this.standardEnabled)
|
||||
this.scoped.InventoryChanged += ScopedOnInventoryChanged;
|
||||
if (!this.rawEnabled)
|
||||
this.scoped.InventoryChangedRaw += ScopedOnInventoryChangedRaw;
|
||||
this.standardEnabled = this.rawEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.Disabled(this.scoped is null))
|
||||
{
|
||||
if (ImGui.Button("Disable##all-disable"))
|
||||
{
|
||||
this.scoped?.Dispose();
|
||||
this.scoped = null;
|
||||
this.standardEnabled = this.rawEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ScopedOnInventoryChangedRaw(IReadOnlyCollection<InventoryEventArgs> events)
|
||||
{
|
||||
var i = 0;
|
||||
foreach (var e in events)
|
||||
Log.Information($"[{++i}/{events.Count}] Raw: {e}");
|
||||
}
|
||||
|
||||
private static void ScopedOnInventoryChanged(IReadOnlyCollection<InventoryEventArgs> events)
|
||||
{
|
||||
var i = 0;
|
||||
foreach (var e in events)
|
||||
{
|
||||
if (e is InventoryComplexEventArgs icea)
|
||||
Log.Information($"[{++i}/{events.Count}] {icea}\n\t├ {icea.SourceEvent}\n\t└ {icea.TargetEvent}");
|
||||
else
|
||||
Log.Information($"[{++i}/{events.Count}] {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using Dalamud.Game.Inventory;
|
||||
using Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
||||
using Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||
|
||||
namespace Dalamud.Plugin.Services;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue