diff --git a/Configuration.cs b/Configuration.cs
index c5c4107..06844eb 100644
--- a/Configuration.cs
+++ b/Configuration.cs
@@ -24,6 +24,8 @@ public class Configuration : IPluginConfiguration {
public int TextMulRed = 100;
public int TextMulGreen = 100;
public int TextMulBlue = 100;
+ public bool ClearResultsOnInactive = true;
+ public float ClearDelaySeconds = 10;
}
public enum MeterMode {
diff --git a/Plugin.cs b/Plugin.cs
index a99b163..2392281 100644
--- a/Plugin.cs
+++ b/Plugin.cs
@@ -3,11 +3,14 @@ using System.Globalization;
using System.Text;
using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
+using Dalamud.Game.Gui.ContextMenu;
+using Dalamud.Game.Text;
using Dalamud.IoC;
using Dalamud.Memory;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
+using FFXIVClientStructs.FFXIV.Client.Game.Group;
using FFXIVClientStructs.FFXIV.Client.Graphics;
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
@@ -37,14 +40,21 @@ public class Plugin : IDalamudPlugin {
[PluginService]
internal ICommandManager CommandManager { get; init; }
+ [PluginService]
+ internal IContextMenu ContextMenu { get; init; }
+
internal Configuration Config { get; }
private Client Client { get; }
internal PluginUi Ui { get; }
private Commands Commands { get; }
- private Stopwatch Watch { get; } = Stopwatch.StartNew();
+ private Stopwatch AlternateWatch { get; } = Stopwatch.StartNew();
+ private Stopwatch DelayWatch { get; } = new();
private bool _ranLastTick;
private bool _showDps = true;
+ private bool _reset;
+ private bool _wasActive;
+ private bool _manuallyReset = true;
private readonly byte[] _manaUsers = [
6, // cnj
@@ -70,9 +80,11 @@ public class Plugin : IDalamudPlugin {
this.Commands = new Commands(this);
this.AddonLifecycle!.RegisterListener(AddonEvent.PostUpdate, "_PartyList", this.UpdateList);
+ this.ContextMenu!.OnMenuOpened += this.MenuOpened;
}
public void Dispose() {
+ this.ContextMenu.OnMenuOpened -= this.MenuOpened;
this.AddonLifecycle.UnregisterListener(AddonEvent.PostUpdate, "_PartyList", this.UpdateList);
this.Commands.Dispose();
this.Ui.Dispose();
@@ -83,24 +95,114 @@ public class Plugin : IDalamudPlugin {
this.Interface.SavePluginConfig(this.Config);
}
+ private unsafe void MenuOpened(IMenuOpenedArgs args) {
+ var add = args.AddonName == "_PartyList";
+ if (!add) {
+ var ctx = AgentContext.Instance();
+ if (args.AgentPtr != (nint) ctx) {
+ return;
+ }
+
+ var targetId = ctx->TargetObjectId.ObjectId;
+ if (targetId == 0xE000_0000) {
+ return;
+ }
+
+ if (this.ClientState.LocalPlayer is { } player && player.GameObjectId == targetId) {
+ add = true;
+ } else {
+ var group = GroupManager.Instance()->GetGroup();
+ if (group != null && group->GetPartyMemberByEntityId(targetId) != null) {
+ add = true;
+ }
+ }
+ }
+
+ if (!add) {
+ return;
+ }
+
+ args.AddMenuItem(new MenuItem {
+ Name = "Clear parse results",
+ Prefix = SeIconChar.BoxedLetterP,
+ PrefixColor = 37,
+ IsEnabled = this.Client.Data?.IsActive == false,
+ OnClicked = _ => {
+ this._reset = true;
+ this._manuallyReset = true;
+ },
+ });
+ }
+
private unsafe void UpdateList(AddonEvent type, AddonArgs args) {
var ranLast = this._ranLastTick;
this._ranLastTick = false;
var list = (AddonPartyList*) AtkStage.Instance()->RaptureAtkUnitManager->GetAddonByName("_PartyList");
- if (!this.UpdateListInner(list) && ranLast) {
+ if (list == null) {
+ return;
+ }
+
+ var shouldUpdate = false;
+
+ var wasActive = this._wasActive;
+ var becameInactive = false;
+ if (this.Client.Data is { } data) {
+ if (wasActive && !data.IsActive) {
+ becameInactive = true;
+ }
+
+ this._wasActive = data.IsActive;
+ }
+
+ if (this.Client.Data is { IsActive: true }) {
+ shouldUpdate = true;
+ this._manuallyReset = false;
+ } else if (becameInactive) {
+ if (this.Config.ClearResultsOnInactive) {
+ this.DelayWatch.Restart();
+ }
+ }
+
+ if (this.Config.ClearResultsOnInactive && this.DelayWatch.IsRunning && this.DelayWatch.Elapsed >= TimeSpan.FromSeconds(this.Config.ClearDelaySeconds)) {
+ this.DelayWatch.Reset();
+ this._reset = true;
+ }
+
+ if (!this._reset && !this._manuallyReset) {
+ // only do these checks if we shouldn't reset and if we're waiting for active data
+
+ // keep running if we're in the delay period
+ if (this.DelayWatch.IsRunning) {
+ shouldUpdate = true;
+ }
+
+ // keep running if the user wants to manually clear results
+ if (!this.Config.ClearResultsOnInactive) {
+ shouldUpdate = true;
+ }
+ }
+
+ if (this._reset) {
+ this.DelayWatch.Reset();
+ this._reset = false;
+ this._manuallyReset = true;
+ this.ResetMembers(list);
+ }
+
+ if (shouldUpdate && this.UpdateListInner(list) && ranLast) {
this.ResetMembers(list);
}
}
+ ///
+ /// Update the party list.
+ ///
+ /// true if the list should be reset immediately
private unsafe bool UpdateListInner(AddonPartyList* list) {
if (this.Client.Data is not { } data) {
return false;
}
- if (!data.IsActive) {
- return false;
- }
-
if (this.ClientState.LocalPlayer is not { } player) {
return false;
}
@@ -109,7 +211,7 @@ public class Plugin : IDalamudPlugin {
var playerName = player.Name.TextValue;
if (list->HoveredIndex >= 0 || list->TargetedIndex >= 0) {
- return false;
+ return true;
}
var names = new List<(string, int)>();
@@ -122,7 +224,7 @@ public class Plugin : IDalamudPlugin {
// controller soft target not handled by hoveredindex above
if (chara->GetSoftTargetId() == member.EntityId) {
- return false;
+ return true;
}
var name = MemoryHelper.ReadStringNullTerminated((nint) member.Name);
@@ -131,8 +233,8 @@ public class Plugin : IDalamudPlugin {
this._ranLastTick = true;
- if (this.Watch.Elapsed.TotalMilliseconds > this.Config.AlternateSeconds * 1_000) {
- this.Watch.Restart();
+ if (this.AlternateWatch.Elapsed.TotalMilliseconds > this.Config.AlternateSeconds * 1_000) {
+ this.AlternateWatch.Restart();
this._showDps ^= true;
}
@@ -150,7 +252,7 @@ public class Plugin : IDalamudPlugin {
this.UpdateMember(list->PartyMembers[i], member.Object, data.Encounter, combatant);
}
- return true;
+ return false;
}
private unsafe void ResetMembers(AddonPartyList* list) {
diff --git a/PluginUi.cs b/PluginUi.cs
index fe6409f..0956f39 100644
--- a/PluginUi.cs
+++ b/PluginUi.cs
@@ -75,7 +75,7 @@ public class PluginUi : IDisposable {
this.Plugin.Config.TextColour = ConvertRgba(textColour);
}
- if (ImGui.TreeNodeEx("Advanced colour options")) {
+ if (ImGui.TreeNodeEx("Advanced colour options##text")) {
using var treePop = new OnDispose(ImGui.TreePop);
anyChanged |= ImGui.SliderInt("Add red", ref this.Plugin.Config.TextAddRed, 0, 255);
@@ -86,6 +86,11 @@ public class PluginUi : IDisposable {
anyChanged |= ImGui.SliderInt("Multiply blue", ref this.Plugin.Config.TextMulBlue, 0, 100);
}
+ anyChanged |= ImGui.Checkbox("Clear results after encounter ends", ref this.Plugin.Config.ClearResultsOnInactive);
+ using (ImGuiHelper.DisabledUnless(this.Plugin.Config.ClearResultsOnInactive)) {
+ anyChanged |= ImGui.SliderFloat("Seconds to delay before clearing", ref this.Plugin.Config.ClearDelaySeconds, 0, 300);
+ }
+
if (anyChanged) {
this.Plugin.SaveConfig();
}