mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-01-02 13:53:40 +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.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||||
using Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
using Dalamud.IoC.Internal;
|
using Dalamud.IoC.Internal;
|
||||||
using Dalamud.Logging.Internal;
|
using Dalamud.Logging.Internal;
|
||||||
|
using Dalamud.Plugin.Internal;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
|
||||||
using Serilog.Events;
|
|
||||||
|
|
||||||
namespace Dalamud.Game.Inventory;
|
namespace Dalamud.Game.Inventory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -18,9 +16,10 @@ namespace Dalamud.Game.Inventory;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[InterfaceVersion("1.0")]
|
[InterfaceVersion("1.0")]
|
||||||
[ServiceManager.BlockingEarlyLoadedService]
|
[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<InventoryItemAddedArgs> addedEvents = new();
|
||||||
private readonly List<InventoryItemRemovedArgs> removedEvents = new();
|
private readonly List<InventoryItemRemovedArgs> removedEvents = new();
|
||||||
|
|
@ -32,120 +31,58 @@ internal class GameInventory : IDisposable, IServiceType, IGameInventory
|
||||||
[ServiceManager.ServiceDependency]
|
[ServiceManager.ServiceDependency]
|
||||||
private readonly Framework framework = Service<Framework>.Get();
|
private readonly Framework framework = Service<Framework>.Get();
|
||||||
|
|
||||||
[ServiceManager.ServiceDependency]
|
|
||||||
private readonly DalamudConfiguration dalamudConfiguration = Service<DalamudConfiguration>.Get();
|
|
||||||
|
|
||||||
private readonly GameInventoryType[] inventoryTypes;
|
private readonly GameInventoryType[] inventoryTypes;
|
||||||
private readonly GameInventoryItem[]?[] inventoryItems;
|
private readonly GameInventoryItem[]?[] inventoryItems;
|
||||||
|
|
||||||
|
private bool subscribersChanged;
|
||||||
|
|
||||||
[ServiceManager.ServiceConstructor]
|
[ServiceManager.ServiceConstructor]
|
||||||
private GameInventory()
|
private GameInventory()
|
||||||
{
|
{
|
||||||
this.inventoryTypes = Enum.GetValues<GameInventoryType>();
|
this.inventoryTypes = Enum.GetValues<GameInventoryType>();
|
||||||
this.inventoryItems = new GameInventoryItem[this.inventoryTypes.Length][];
|
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/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
this.framework.Update -= this.OnFrameworkUpdate;
|
lock (this.subscribersPendingChange)
|
||||||
}
|
|
||||||
|
|
||||||
private static void InvokeSafely(
|
|
||||||
IGameInventory.InventoryChangelogDelegate? cb,
|
|
||||||
IReadOnlyCollection<InventoryEventArgs> data)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
cb?.Invoke(data);
|
this.subscribers.Clear();
|
||||||
}
|
this.subscribersPendingChange.Clear();
|
||||||
catch (Exception e)
|
this.subscribersChanged = false;
|
||||||
{
|
this.framework.Update -= this.OnFrameworkUpdate;
|
||||||
Log.Error(e, "Exception during batch callback");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InvokeSafely(IGameInventory.InventoryChangedDelegate? cb, InventoryEventArgs arg)
|
/// <summary>
|
||||||
|
/// Subscribe to events.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s">The event target.</param>
|
||||||
|
public void Subscribe(GameInventoryPluginScoped s)
|
||||||
{
|
{
|
||||||
try
|
lock (this.subscribersPendingChange)
|
||||||
{
|
{
|
||||||
cb?.Invoke(arg.Type, arg);
|
this.subscribersPendingChange.Add(s);
|
||||||
}
|
this.subscribersChanged = true;
|
||||||
catch (Exception e)
|
if (this.subscribersPendingChange.Count == 1)
|
||||||
{
|
this.framework.Update += this.OnFrameworkUpdate;
|
||||||
Log.Error(e, "Exception during {argType} callback", arg.Type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InvokeSafely<T>(IGameInventory.InventoryChangedDelegate<T>? cb, T arg)
|
/// <summary>
|
||||||
where T : InventoryEventArgs
|
/// Unsubscribe from events.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s">The event target.</param>
|
||||||
|
public void Unsubscribe(GameInventoryPluginScoped s)
|
||||||
{
|
{
|
||||||
try
|
lock (this.subscribersPendingChange)
|
||||||
{
|
{
|
||||||
cb?.Invoke(arg);
|
if (!this.subscribersPendingChange.Remove(s))
|
||||||
}
|
return;
|
||||||
catch (Exception e)
|
this.subscribersChanged = true;
|
||||||
{
|
if (this.subscribersPendingChange.Count == 0)
|
||||||
Log.Error(e, "Exception during {argType} callback", arg.Type);
|
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)
|
if (this.addedEvents.Count == 0 && this.removedEvents.Count == 0 && this.changedEvents.Count == 0)
|
||||||
return;
|
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.
|
// Broadcast InventoryChangedRaw.
|
||||||
// Same reason with the above on why are there 3 lists of events involved.
|
// Same reason with the above on why are there 3 lists of events involved.
|
||||||
InvokeSafely(
|
var allRawEventsCollection = new DeferredReadOnlyCollection<InventoryEventArgs>(
|
||||||
this.InventoryChangedRaw,
|
this.addedEvents.Count +
|
||||||
new DeferredReadOnlyCollection<InventoryEventArgs>(
|
this.removedEvents.Count +
|
||||||
this.addedEvents.Count +
|
this.changedEvents.Count,
|
||||||
this.removedEvents.Count +
|
() => Array.Empty<InventoryEventArgs>()
|
||||||
this.changedEvents.Count,
|
.Concat(this.addedEvents)
|
||||||
() => Array.Empty<InventoryEventArgs>()
|
.Concat(this.removedEvents)
|
||||||
.Concat(this.addedEvents)
|
.Concat(this.changedEvents));
|
||||||
.Concat(this.removedEvents)
|
foreach (var s in this.subscribers)
|
||||||
.Concat(this.changedEvents)));
|
s.InvokeChangedRaw(allRawEventsCollection);
|
||||||
|
|
||||||
// Resolve moved items, from 1 added + 1 removed event.
|
// Resolve moved items, from 1 added + 1 removed event.
|
||||||
for (var iAdded = this.addedEvents.Count - 1; iAdded >= 0; --iAdded)
|
for (var iAdded = this.addedEvents.Count - 1; iAdded >= 0; --iAdded)
|
||||||
|
|
@ -291,58 +250,32 @@ internal class GameInventory : IDisposable, IServiceType, IGameInventory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a collection view of all events.
|
||||||
|
var allEventsCollection = new DeferredReadOnlyCollection<InventoryEventArgs>(
|
||||||
|
this.addedEvents.Count +
|
||||||
|
this.removedEvents.Count +
|
||||||
|
this.changedEvents.Count +
|
||||||
|
this.movedEvents.Count +
|
||||||
|
this.splitEvents.Count +
|
||||||
|
this.mergedEvents.Count,
|
||||||
|
() => Array.Empty<InventoryEventArgs>()
|
||||||
|
.Concat(this.addedEvents)
|
||||||
|
.Concat(this.removedEvents)
|
||||||
|
.Concat(this.changedEvents)
|
||||||
|
.Concat(this.movedEvents)
|
||||||
|
.Concat(this.splitEvents)
|
||||||
|
.Concat(this.mergedEvents));
|
||||||
|
|
||||||
// Broadcast the rest.
|
// Broadcast the rest.
|
||||||
InvokeSafely(
|
foreach (var s in this.subscribers)
|
||||||
this.InventoryChanged,
|
|
||||||
new DeferredReadOnlyCollection<InventoryEventArgs>(
|
|
||||||
this.addedEvents.Count +
|
|
||||||
this.removedEvents.Count +
|
|
||||||
this.changedEvents.Count +
|
|
||||||
this.movedEvents.Count +
|
|
||||||
this.splitEvents.Count +
|
|
||||||
this.mergedEvents.Count,
|
|
||||||
() => Array.Empty<InventoryEventArgs>()
|
|
||||||
.Concat(this.addedEvents)
|
|
||||||
.Concat(this.removedEvents)
|
|
||||||
.Concat(this.changedEvents)
|
|
||||||
.Concat(this.movedEvents)
|
|
||||||
.Concat(this.splitEvents)
|
|
||||||
.Concat(this.mergedEvents)));
|
|
||||||
|
|
||||||
foreach (var x in this.addedEvents)
|
|
||||||
{
|
{
|
||||||
InvokeSafely(this.ItemAdded, x);
|
s.InvokeChanged(allEventsCollection);
|
||||||
InvokeSafely(this.ItemAddedExplicit, x);
|
s.Invoke(this.addedEvents);
|
||||||
}
|
s.Invoke(this.removedEvents);
|
||||||
|
s.Invoke(this.changedEvents);
|
||||||
foreach (var x in this.removedEvents)
|
s.Invoke(this.movedEvents);
|
||||||
{
|
s.Invoke(this.splitEvents);
|
||||||
InvokeSafely(this.ItemRemoved, x);
|
s.Invoke(this.mergedEvents);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're done using the lists. Clean them up.
|
// We're done using the lists. Clean them up.
|
||||||
|
|
@ -388,29 +321,15 @@ internal class GameInventory : IDisposable, IServiceType, IGameInventory
|
||||||
#pragma warning restore SA1015
|
#pragma warning restore SA1015
|
||||||
internal class GameInventoryPluginScoped : IDisposable, IServiceType, IGameInventory
|
internal class GameInventoryPluginScoped : IDisposable, IServiceType, IGameInventory
|
||||||
{
|
{
|
||||||
|
private static readonly ModuleLog Log = new(nameof(GameInventoryPluginScoped));
|
||||||
|
|
||||||
[ServiceManager.ServiceDependency]
|
[ServiceManager.ServiceDependency]
|
||||||
private readonly GameInventory gameInventoryService = Service<GameInventory>.Get();
|
private readonly GameInventory gameInventoryService = Service<GameInventory>.Get();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="GameInventoryPluginScoped"/> class.
|
/// Initializes a new instance of the <see cref="GameInventoryPluginScoped"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GameInventoryPluginScoped()
|
public GameInventoryPluginScoped() => this.gameInventoryService.Subscribe(this);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public event IGameInventory.InventoryChangelogDelegate? InventoryChanged;
|
public event IGameInventory.InventoryChangelogDelegate? InventoryChanged;
|
||||||
|
|
@ -457,20 +376,7 @@ internal class GameInventoryPluginScoped : IDisposable, IServiceType, IGameInven
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
this.gameInventoryService.InventoryChanged -= this.OnInventoryChangedForward;
|
this.gameInventoryService.Unsubscribe(this);
|
||||||
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.InventoryChanged = null;
|
this.InventoryChanged = null;
|
||||||
this.InventoryChangedRaw = null;
|
this.InventoryChangedRaw = null;
|
||||||
|
|
@ -488,45 +394,122 @@ internal class GameInventoryPluginScoped : IDisposable, IServiceType, IGameInven
|
||||||
this.ItemMergedExplicit = null;
|
this.ItemMergedExplicit = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInventoryChangedForward(IReadOnlyCollection<InventoryEventArgs> events)
|
/// <summary>
|
||||||
=> this.InventoryChanged?.Invoke(events);
|
/// 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)
|
/// <summary>
|
||||||
=> this.InventoryChangedRaw?.Invoke(events);
|
/// 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)
|
// Note below: using List<T> instead of IEnumerable<T>, since List<T> has a specialized lightweight enumerator.
|
||||||
=> this.ItemAdded?.Invoke(type, data);
|
|
||||||
|
|
||||||
private void OnInventoryItemRemovedForward(GameInventoryEvent type, InventoryEventArgs data)
|
/// <summary>
|
||||||
=> this.ItemRemoved?.Invoke(type, data);
|
/// 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)
|
/// <summary>
|
||||||
=> this.ItemChanged?.Invoke(type, data);
|
/// 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)
|
/// <summary>
|
||||||
=> this.ItemMoved?.Invoke(type, data);
|
/// 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)
|
/// <summary>
|
||||||
=> this.ItemSplit?.Invoke(type, data);
|
/// 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)
|
/// <summary>
|
||||||
=> this.ItemMerged?.Invoke(type, data);
|
/// 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)
|
/// <summary>
|
||||||
=> this.ItemAddedExplicit?.Invoke(data);
|
/// 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)
|
private static void Invoke<T>(
|
||||||
=> this.ItemRemovedExplicit?.Invoke(data);
|
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)
|
try
|
||||||
=> this.ItemChangedExplicit?.Invoke(data);
|
{
|
||||||
|
cbt?.Invoke(evt);
|
||||||
private void OnInventoryItemMovedExplicitForward(InventoryItemMovedArgs data)
|
}
|
||||||
=> this.ItemMovedExplicit?.Invoke(data);
|
catch (Exception e)
|
||||||
|
{
|
||||||
private void OnInventoryItemSplitExplicitForward(InventoryItemSplitArgs data)
|
Log.Error(
|
||||||
=> this.ItemSplitExplicit?.Invoke(data);
|
e,
|
||||||
|
"[{plugin}] Exception during typed callback for {evt}",
|
||||||
private void OnInventoryItemMergedExplicitForward(InventoryItemMergedArgs data)
|
Service<PluginManager>.GetNullable()?.FindCallingPlugin(new(e))?.Name ?? "(unknown plugin)",
|
||||||
=> this.ItemMergedExplicit?.Invoke(data);
|
evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the data associated with an item being affected across different slots, possibly in different containers.
|
/// 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>
|
/// <summary>
|
||||||
/// Abstract base class representing inventory changed events.
|
/// Abstract base class representing inventory changed events.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
namespace Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the data associated with an item being added to an inventory.
|
/// 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>
|
/// <summary>
|
||||||
/// Represents the data associated with an items properties being changed.
|
/// 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>
|
/// <summary>
|
||||||
/// Represents the data associated with an item being merged from two stacks into one.
|
/// 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>
|
/// <summary>
|
||||||
/// Represents the data associated with an item being moved from one inventory and added to another.
|
/// 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>
|
/// <summary>
|
||||||
/// Represents the data associated with an item being removed from an inventory.
|
/// 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>
|
/// <summary>
|
||||||
/// Represents the data associated with an item being split from one stack into two.
|
/// 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 FateTableWidget(),
|
||||||
new FlyTextWidget(),
|
new FlyTextWidget(),
|
||||||
new FontAwesomeTestWidget(),
|
new FontAwesomeTestWidget(),
|
||||||
|
new GameInventoryTestWidget(),
|
||||||
new GamepadWidget(),
|
new GamepadWidget(),
|
||||||
new GaugeWidget(),
|
new GaugeWidget(),
|
||||||
new HookWidget(),
|
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 System.Collections.Generic;
|
||||||
|
|
||||||
using Dalamud.Game.Inventory;
|
using Dalamud.Game.Inventory;
|
||||||
using Dalamud.Game.Inventory.InventoryChangeArgsTypes;
|
using Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||||
|
|
||||||
namespace Dalamud.Plugin.Services;
|
namespace Dalamud.Plugin.Services;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue