feat: add configuration and modes

This commit is contained in:
Anna 2024-07-25 02:50:32 -04:00
parent 09266c4e5f
commit 05e2d87142
Signed by: anna
GPG Key ID: D0943384CD9F87D1
6 changed files with 281 additions and 32 deletions

21
Commands.cs Normal file
View File

@ -0,0 +1,21 @@
using Dalamud.Game.Command;
namespace PartyDamage;
public class Commands : IDisposable {
private Plugin Plugin { get; }
public Commands(Plugin plugin) {
this.Plugin = plugin;
this.Plugin.CommandManager.AddHandler("/partydamage", new CommandInfo(this.OnCommand));
}
public void Dispose() {
this.Plugin.CommandManager.RemoveHandler("/partydamage");
}
private void OnCommand(string command, string args) {
this.Plugin.Ui.Visible ^= true;
}
}

20
Configuration.cs Normal file
View File

@ -0,0 +1,20 @@
using Dalamud.Configuration;
namespace PartyDamage;
public class Configuration : IPluginConfiguration {
public int Version { get; set; } = 1;
public bool UseDpsBar = true;
public float BarAlpha = 0.5f;
public MeterMode Mode = MeterMode.Mana;
public bool Alternate = true;
public bool ManaModeAlternateOnlyManaUsers = true;
public float AlternateSeconds = 3.0f;
public uint DpsColour = 0xEDFFEC;
}
public enum MeterMode {
Name,
Mana,
}

18
ImGuiHelper.cs Normal file
View File

@ -0,0 +1,18 @@
using ImGuiNET;
namespace PartyDamage;
public static class ImGuiHelper {
public static OnDispose? DisabledIf(bool disabled) {
if (disabled) {
ImGui.BeginDisabled();
return new OnDispose(ImGui.EndDisabled);
}
return null;
}
public static OnDispose? DisabledUnless(bool unless) {
return DisabledIf(!unless);
}
}

19
OnDispose.cs Normal file
View File

@ -0,0 +1,19 @@
namespace PartyDamage;
public class OnDispose : IDisposable {
private readonly Action _action;
private bool _disposed;
public OnDispose(Action action) {
this._action = action;
}
public void Dispose() {
if (this._disposed) {
return;
}
this._disposed = true;
this._action();
}
}

159
Plugin.cs
View File

@ -31,23 +31,56 @@ public class Plugin : IDalamudPlugin {
private IPartyList PartyList { get; init; }
[PluginService]
private IDalamudPluginInterface Interface { get; init; }
internal IDalamudPluginInterface Interface { get; init; }
[PluginService]
internal ICommandManager CommandManager { 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 bool _ranLastTick;
private readonly byte[] ManaUsers = [
6, // cnj
7, // thm
19, // pld
24, // whm
25, // blm
26, // acn
27, // smn
28, // sch
32, // drk
33, // ast
35, // rdm
36, // blu
40, // sge
42, // pct
];
public Plugin() {
this.Config = this.Interface!.GetPluginConfig() as Configuration ?? new Configuration();
this.Client = new Client();
this.Ui = new PluginUi(this);
this.Commands = new Commands(this);
this.AddonLifecycle!.RegisterListener(AddonEvent.PostUpdate, "_PartyList", this.UpdateList);
}
public void Dispose() {
this.AddonLifecycle.UnregisterListener(AddonEvent.PostUpdate, "_PartyList", this.UpdateList);
this.Commands.Dispose();
this.Ui.Dispose();
this.Client.Dispose();
}
internal void SaveConfig() {
this.Interface.SavePluginConfig(this.Config);
}
private unsafe void UpdateList(AddonEvent type, AddonArgs args) {
var ranLast = this._ranLastTick;
this._ranLastTick = false;
@ -140,6 +173,11 @@ public class Plugin : IDalamudPlugin {
var manaString = member.Object->Mana.ToString(CultureInfo.InvariantCulture);
left->SetText(manaString[..^2]);
right->SetText(manaString[^2..]);
unit.Name->SetText(member.Object->Name);
unit.Name->TextColor = new ByteColor {
RGBA = 0xFFFFFFFF,
};
}
}
@ -149,46 +187,103 @@ public class Plugin : IDalamudPlugin {
Encounter encounter,
Combatant combatant
) {
member.TargetGlow->ToggleVisibility(true);
member.TargetGlow->SetAlpha(128);
member.TargetGlow->SetScaleX(
encounter.EncDps == 0
? 0
: combatant.EncDps / encounter.EncDps
);
if (this.Config.UseDpsBar) {
member.TargetGlow->ToggleVisibility(true);
member.TargetGlow->SetAlpha((byte) Math.Round(this.Config.BarAlpha * 255));
member.TargetGlow->SetScaleX(
encounter.EncDps == 0
? 0
: combatant.EncDps / encounter.EncDps
);
}
var left = (AtkTextNode*) member.MPGaugeBar->GetTextNodeById(2);
var right = (AtkTextNode*) member.MPGaugeBar->GetTextNodeById(3);
if (this.Config.Mode == MeterMode.Mana) {
var left = (AtkTextNode*) member.MPGaugeBar->GetTextNodeById(2);
var right = (AtkTextNode*) member.MPGaugeBar->GetTextNodeById(3);
if (this.Config.Alternate) {
var isCaster = Array.IndexOf(this.ManaUsers, chara->ClassJob) != -1;
if (!this.Config.ManaModeAlternateOnlyManaUsers || isCaster) {
var elapsedSeconds = this.Watch.Elapsed.Seconds;
if (elapsedSeconds >= this.Config.AlternateSeconds * 2) {
this.Watch.Restart();
} else if (elapsedSeconds >= this.Config.AlternateSeconds) {
left->TextColor = new ByteColor {
RGBA = 0xFFFFFFFF,
};
right->TextColor = left->TextColor;
var manaString = chara->Mana.ToString(CultureInfo.InvariantCulture);
left->SetText(manaString[..^2]);
right->SetText(manaString[^2..]);
if (this.Watch.Elapsed.Seconds >= this.Config.AlternateSeconds * 2) {
this.Watch.Restart();
}
return;
}
}
}
if (this.Watch.Elapsed.Seconds % 6 < 3) {
left->TextColor = new ByteColor {
RGBA = 0xFFFFFFFF,
RGBA = this.Config.DpsColour,
};
right->TextColor = left->TextColor;
var manaString = chara->Mana.ToString(CultureInfo.InvariantCulture);
left->SetText(manaString[..^2]);
right->SetText(manaString[^2..]);
if (combatant.EncDps == 0 || float.IsInfinity(combatant.EncDps) || float.IsNaN(combatant.EncDps)) {
left->SetText("0.");
right->SetText("00");
} else if (combatant.EncDps < 1_000) {
var dps = Math.Round(combatant.EncDps * 100).ToString(CultureInfo.InvariantCulture);
left->SetText($"{dps[..^2]}.");
right->SetText(dps[^2..]);
} else if (combatant.EncDps < 1_000_000) {
var dps = Math.Round(combatant.EncDps / 100).ToString(CultureInfo.InvariantCulture);
left->SetText($"{dps[..^1]}.");
right->SetText($"{dps[^1..]}K");
} else if (combatant.EncDps < 1_000_000_000) {
var dps = Math.Round(combatant.EncDps / 100_000).ToString(CultureInfo.InvariantCulture);
left->SetText($"{dps[..^1]}.");
right->SetText($"{dps[^1..]}M");
} else {
var dps = Math.Round(combatant.EncDps / 100_000_000).ToString(CultureInfo.InvariantCulture);
left->SetText($"{dps[..^1]}.");
right->SetText($"{dps[^1..]}B");
}
} else if (this.Config.Mode == MeterMode.Name) {
var dpsText = combatant.EncDps switch {
float.NaN => "0",
float.PositiveInfinity => "0",
float.NegativeInfinity => "0",
< 1_000 => $"{combatant.EncDps:N2}",
< 1_000_000 => $"{combatant.EncDps / 1_000:N2}K",
< 1_000_000_000 => $"{combatant.EncDps / 1_000_000:N2}M",
_ => $"{combatant.EncDps / 1_000_000_000:N2}B",
};
return;
}
if (this.Config.Alternate) {
var elapsedSeconds = this.Watch.Elapsed.Seconds;
if (elapsedSeconds >= this.Config.AlternateSeconds * 2) {
this.Watch.Restart();
} else if (elapsedSeconds >= this.Config.AlternateSeconds) {
member.Name->TextColor = new ByteColor {
RGBA = 0xFFFFFFFF,
};
member.Name->SetText(chara->Name);
left->TextColor = new ByteColor {
RGBA = 0xedffecff,
};
right->TextColor = left->TextColor;
if (this.Watch.Elapsed.Seconds >= this.Config.AlternateSeconds * 2) {
this.Watch.Restart();
}
if (combatant.EncDps == 0 || float.IsInfinity(combatant.EncDps) || float.IsNaN(combatant.EncDps)) {
left->SetText("0.");
right->SetText("00");
} else if (combatant.EncDps < 1_000) {
var dps = Math.Round(combatant.EncDps * 100).ToString(CultureInfo.InvariantCulture);
left->SetText($"{dps[..^2]}.");
right->SetText(dps[^2..]);
} else if (combatant.EncDps < 1_000_000) {
var dps = Math.Round(combatant.EncDps / 100).ToString(CultureInfo.InvariantCulture);
left->SetText($"{dps[..^1]}.");
right->SetText($"{dps[^1..]}K");
return;
}
}
member.Name->SetText(dpsText);
member.Name->TextColor = new ByteColor {
RGBA = this.Config.DpsColour,
};
}
}
}

76
PluginUi.cs Normal file
View File

@ -0,0 +1,76 @@
using System.Numerics;
using ImGuiNET;
namespace PartyDamage;
public class PluginUi : IDisposable {
private Plugin Plugin { get; }
internal bool Visible;
public PluginUi(Plugin plugin) {
this.Plugin = plugin;
this.Plugin.Interface.UiBuilder.Draw += this.Draw;
}
public void Dispose() {
this.Plugin.Interface.UiBuilder.Draw -= this.Draw;
}
private void Draw() {
var anyChanged = false;
ImGui.TextUnformatted("Meter mode");
if (ImGui.BeginCombo("##mode", Enum.GetName(this.Plugin.Config.Mode))) {
using var endCombo = new OnDispose(ImGui.EndCombo);
foreach (var mode in Enum.GetValues<MeterMode>()) {
if (ImGui.Selectable(Enum.GetName(mode), mode == this.Plugin.Config.Mode)) {
anyChanged = true;
this.Plugin.Config.Mode = mode;
}
}
}
anyChanged |= ImGui.Checkbox("Use DPS bars behind party list", ref this.Plugin.Config.UseDpsBar);
var barAlpha = this.Plugin.Config.BarAlpha * 100;
if (ImGui.SliderFloat("Bar opacity", ref barAlpha, 0, 100, "%.2f%%")) {
this.Plugin.Config.BarAlpha = Math.Clamp(barAlpha / 100, 0, 1);
}
anyChanged |= ImGui.Checkbox("Alternate between values", ref this.Plugin.Config.Alternate);
using (ImGuiHelper.DisabledUnless(this.Plugin.Config.Alternate)) {
anyChanged |= ImGui.SliderFloat("Seconds before alternating", ref this.Plugin.Config.AlternateSeconds, 0.5f, 60f);
}
using (ImGuiHelper.DisabledUnless(this.Plugin.Config.Alternate && this.Plugin.Config.Mode == MeterMode.Name)) {
anyChanged |= ImGui.Checkbox("Only alternate on jobs that use mana", ref this.Plugin.Config.ManaModeAlternateOnlyManaUsers);
}
var textColour = ConvertRgba(this.Plugin.Config.DpsColour);
if (ImGui.ColorPicker3("DPS text colour", ref textColour)) {
anyChanged = true;
this.Plugin.Config.DpsColour = ConvertRgba(textColour);
}
}
private static Vector3 ConvertRgba(uint colour) {
var red = colour & 0xFF;
var green = (colour >> 8) & 0xFF;
var blue = (colour >> 16) & 0xFF;
// var alpha = colour >> 24;
return new Vector3(red / 255f, green / 255f, blue / 255f);
}
private static uint ConvertRgba(Vector3 parts) {
var red = (uint) Math.Round(parts.X * 255);
var green = (uint) Math.Round(parts.Y * 255);
var blue = (uint) Math.Round(parts.Z * 255);
return (red << 24)
| (green << 16)
| (blue << 8)
| 0xFF;
}
}