feat: add clearing settings

This commit is contained in:
Anna 2024-07-25 18:21:46 -04:00
parent 867203a86c
commit e471548e81
Signed by: anna
GPG Key ID: D0943384CD9F87D1
3 changed files with 121 additions and 12 deletions

View File

@ -24,6 +24,8 @@ public class Configuration : IPluginConfiguration {
public int TextMulRed = 100; public int TextMulRed = 100;
public int TextMulGreen = 100; public int TextMulGreen = 100;
public int TextMulBlue = 100; public int TextMulBlue = 100;
public bool ClearResultsOnInactive = true;
public float ClearDelaySeconds = 10;
} }
public enum MeterMode { public enum MeterMode {

124
Plugin.cs
View File

@ -3,11 +3,14 @@ using System.Globalization;
using System.Text; using System.Text;
using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
using Dalamud.Game.Gui.ContextMenu;
using Dalamud.Game.Text;
using Dalamud.IoC; using Dalamud.IoC;
using Dalamud.Memory; using Dalamud.Memory;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Group;
using FFXIVClientStructs.FFXIV.Client.Graphics; using FFXIVClientStructs.FFXIV.Client.Graphics;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Client.UI.Agent;
@ -37,14 +40,21 @@ public class Plugin : IDalamudPlugin {
[PluginService] [PluginService]
internal ICommandManager CommandManager { get; init; } internal ICommandManager CommandManager { get; init; }
[PluginService]
internal IContextMenu ContextMenu { get; init; }
internal Configuration Config { get; } internal Configuration Config { get; }
private Client Client { get; } private Client Client { get; }
internal PluginUi Ui { get; } internal PluginUi Ui { get; }
private Commands Commands { 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 _ranLastTick;
private bool _showDps = true; private bool _showDps = true;
private bool _reset;
private bool _wasActive;
private bool _manuallyReset = true;
private readonly byte[] _manaUsers = [ private readonly byte[] _manaUsers = [
6, // cnj 6, // cnj
@ -70,9 +80,11 @@ public class Plugin : IDalamudPlugin {
this.Commands = new Commands(this); this.Commands = new Commands(this);
this.AddonLifecycle!.RegisterListener(AddonEvent.PostUpdate, "_PartyList", this.UpdateList); this.AddonLifecycle!.RegisterListener(AddonEvent.PostUpdate, "_PartyList", this.UpdateList);
this.ContextMenu!.OnMenuOpened += this.MenuOpened;
} }
public void Dispose() { public void Dispose() {
this.ContextMenu.OnMenuOpened -= this.MenuOpened;
this.AddonLifecycle.UnregisterListener(AddonEvent.PostUpdate, "_PartyList", this.UpdateList); this.AddonLifecycle.UnregisterListener(AddonEvent.PostUpdate, "_PartyList", this.UpdateList);
this.Commands.Dispose(); this.Commands.Dispose();
this.Ui.Dispose(); this.Ui.Dispose();
@ -83,24 +95,114 @@ public class Plugin : IDalamudPlugin {
this.Interface.SavePluginConfig(this.Config); 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) { private unsafe void UpdateList(AddonEvent type, AddonArgs args) {
var ranLast = this._ranLastTick; var ranLast = this._ranLastTick;
this._ranLastTick = false; this._ranLastTick = false;
var list = (AddonPartyList*) AtkStage.Instance()->RaptureAtkUnitManager->GetAddonByName("_PartyList"); 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); this.ResetMembers(list);
} }
} }
/// <summary>
/// Update the party list.
/// </summary>
/// <returns>true if the list should be reset immediately</returns>
private unsafe bool UpdateListInner(AddonPartyList* list) { private unsafe bool UpdateListInner(AddonPartyList* list) {
if (this.Client.Data is not { } data) { if (this.Client.Data is not { } data) {
return false; return false;
} }
if (!data.IsActive) {
return false;
}
if (this.ClientState.LocalPlayer is not { } player) { if (this.ClientState.LocalPlayer is not { } player) {
return false; return false;
} }
@ -109,7 +211,7 @@ public class Plugin : IDalamudPlugin {
var playerName = player.Name.TextValue; var playerName = player.Name.TextValue;
if (list->HoveredIndex >= 0 || list->TargetedIndex >= 0) { if (list->HoveredIndex >= 0 || list->TargetedIndex >= 0) {
return false; return true;
} }
var names = new List<(string, int)>(); var names = new List<(string, int)>();
@ -122,7 +224,7 @@ public class Plugin : IDalamudPlugin {
// controller soft target not handled by hoveredindex above // controller soft target not handled by hoveredindex above
if (chara->GetSoftTargetId() == member.EntityId) { if (chara->GetSoftTargetId() == member.EntityId) {
return false; return true;
} }
var name = MemoryHelper.ReadStringNullTerminated((nint) member.Name); var name = MemoryHelper.ReadStringNullTerminated((nint) member.Name);
@ -131,8 +233,8 @@ public class Plugin : IDalamudPlugin {
this._ranLastTick = true; this._ranLastTick = true;
if (this.Watch.Elapsed.TotalMilliseconds > this.Config.AlternateSeconds * 1_000) { if (this.AlternateWatch.Elapsed.TotalMilliseconds > this.Config.AlternateSeconds * 1_000) {
this.Watch.Restart(); this.AlternateWatch.Restart();
this._showDps ^= true; this._showDps ^= true;
} }
@ -150,7 +252,7 @@ public class Plugin : IDalamudPlugin {
this.UpdateMember(list->PartyMembers[i], member.Object, data.Encounter, combatant); this.UpdateMember(list->PartyMembers[i], member.Object, data.Encounter, combatant);
} }
return true; return false;
} }
private unsafe void ResetMembers(AddonPartyList* list) { private unsafe void ResetMembers(AddonPartyList* list) {

View File

@ -75,7 +75,7 @@ public class PluginUi : IDisposable {
this.Plugin.Config.TextColour = ConvertRgba(textColour); 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); using var treePop = new OnDispose(ImGui.TreePop);
anyChanged |= ImGui.SliderInt("Add red", ref this.Plugin.Config.TextAddRed, 0, 255); 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.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) { if (anyChanged) {
this.Plugin.SaveConfig(); this.Plugin.SaveConfig();
} }