AddonLifecycle ReceiveEvent improvements (#1511)

* Prototype

* Add hook null safety

Add a check to make sure addons that invoke virtual functions for other addons don't trigger lifecycle messages multiple times.

* Expose event listeners for AddonLifecycleWidget.cs

Disable hook when all listeners for an addon unregister

* Add AddonLifecycleWidget.cs

* Remove excess logging
This commit is contained in:
MidoriKami 2023-10-30 19:39:43 -07:00 committed by GitHub
parent d8c3c4c789
commit 67ae069a23
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 346 additions and 80 deletions

View file

@ -50,6 +50,7 @@ internal class DataWindow : Window
new DataShareWidget(),
new NetworkMonitorWidget(),
new IconBrowserWidget(),
new AddonLifecycleWidget(),
};
private readonly IOrderedEnumerable<IDataWindowWidget> orderedModules;

View file

@ -0,0 +1,135 @@
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Linq;
using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Interface.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
/// <summary>
/// Debug widget for displaying AddonLifecycle data.
/// </summary>
public class AddonLifecycleWidget : IDataWindowWidget
{
/// <inheritdoc/>
public string[]? CommandShortcuts { get; init; } = { "AddonLifecycle" };
/// <inheritdoc/>
public string DisplayName { get; init; } = "Addon Lifecycle";
/// <inheritdoc/>
[MemberNotNullWhen(true, "AddonLifecycle")]
public bool Ready { get; set; }
private AddonLifecycle? AddonLifecycle { get; set; }
/// <inheritdoc/>
public void Load()
{
this.AddonLifecycle = Service<AddonLifecycle>.GetNullable();
if (this.AddonLifecycle is not null) this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
if (!this.Ready)
{
ImGui.Text("AddonLifecycle Reference is null, reload module.");
return;
}
if (ImGui.CollapsingHeader("Listeners"))
{
ImGui.Indent();
this.DrawEventListeners();
ImGui.Unindent();
}
if (ImGui.CollapsingHeader("ReceiveEvent Hooks"))
{
ImGui.Indent();
this.DrawReceiveEventHooks();
ImGui.Unindent();
}
}
private void DrawEventListeners()
{
if (!this.Ready) return;
foreach (var eventType in Enum.GetValues<AddonEvent>())
{
if (ImGui.CollapsingHeader(eventType.ToString()))
{
ImGui.Indent();
var listeners = this.AddonLifecycle.EventListeners.Where(listener => listener.EventType == eventType).ToList();
if (!listeners.Any())
{
ImGui.Text("No Listeners Registered for Event");
}
if (ImGui.BeginTable("AddonLifecycleListenersTable", 2))
{
ImGui.TableSetupColumn("##AddonName", ImGuiTableColumnFlags.WidthFixed, 100.0f * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("##MethodInvoke", ImGuiTableColumnFlags.WidthStretch);
foreach (var listener in listeners)
{
ImGui.TableNextColumn();
ImGui.Text(listener.AddonName is "" ? "GLOBAL" : listener.AddonName);
ImGui.TableNextColumn();
ImGui.Text($"{listener.FunctionDelegate.Target}::{listener.FunctionDelegate.Method.Name}");
}
ImGui.EndTable();
}
ImGui.Unindent();
}
}
}
private void DrawReceiveEventHooks()
{
if (!this.Ready) return;
var listeners = this.AddonLifecycle.ReceiveEventListeners;
if (!listeners.Any())
{
ImGui.Text("No ReceiveEvent Hooks are Registered");
}
foreach (var receiveEventListener in this.AddonLifecycle.ReceiveEventListeners)
{
if (ImGui.CollapsingHeader(string.Join(", ", receiveEventListener.AddonNames)))
{
ImGui.Columns(2);
ImGui.Text("Hook Address");
ImGui.NextColumn();
ImGui.Text(receiveEventListener.HookAddress.ToString("X"));
ImGui.NextColumn();
ImGui.Text("Hook Status");
ImGui.NextColumn();
if (receiveEventListener.Hook is null)
{
ImGui.Text("Hook is null");
}
else
{
var color = receiveEventListener.Hook.IsEnabled ? KnownColor.Green.Vector() : KnownColor.OrangeRed.Vector();
var text = receiveEventListener.Hook.IsEnabled ? "Enabled" : "Disabled";
ImGui.TextColored(color, text);
}
ImGui.Columns(1);
}
}
}
}