feat: handle pets

This commit is contained in:
Anna 2024-07-24 18:04:52 -04:00
parent 60d766ced4
commit d93a189c5c
Signed by: anna
GPG Key ID: D0943384CD9F87D1
4 changed files with 154 additions and 96 deletions

View File

@ -6,7 +6,7 @@ using Newtonsoft.Json.Linq;
namespace PartyDamage;
public class Client : IDisposable {
private ClientWebSocket WebSocket { get; }
private ClientWebSocket? WebSocket { get; set; }
private CancellationTokenSource TokenSource { get; }
private Task? MainTask { get; set; }
private bool _disposed;
@ -14,7 +14,6 @@ public class Client : IDisposable {
internal CombatData? Data { get; private set; }
internal Client() {
this.WebSocket = new ClientWebSocket();
this.TokenSource = new CancellationTokenSource();
this.MainTask = Task.Run(async () => {
while (!this._disposed) {
@ -37,10 +36,11 @@ public class Client : IDisposable {
this._disposed = true;
this.TokenSource.Cancel();
this.WebSocket.Dispose();
this.WebSocket?.Dispose();
}
private async Task Main() {
this.WebSocket = new ClientWebSocket();
await this.WebSocket.ConnectAsync(new Uri("ws://127.0.0.1:10501/ws"), this.TokenSource.Token);
const string msg = "{\"call\": \"subscribe\", \"events\": [\"CombatData\"]}";
var msgBytes = Encoding.UTF8.GetBytes(msg);
@ -60,8 +60,13 @@ public class Client : IDisposable {
var jobj = JObject.Parse(text);
if (jobj["type"]?.Value<string>() == "CombatData") {
var data = JsonConvert.DeserializeObject<CombatData>(text);
this.Data = data;
var data = JsonConvert.DeserializeObject<RawCombatData>(text);
if (data == null) {
this.Data = null;
continue;
}
this.Data = new CombatData(data);
}
}

View File

@ -1,89 +1,38 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace PartyDamage;
[Serializable]
public class CombatData {
public Encounter Encounter;
public Encounter Encounter { get; }
public Dictionary<string, Combatant> Combatants { get; } = [];
[JsonProperty("Combatant")]
public Dictionary<string, Combatant> Combatants;
public CombatData(RawCombatData raw) {
foreach (var (key, value) in raw.Combatants) {
this.Combatants[key] = new Combatant {
Name = value.Name,
EncDps = TryFloat(value.EncDps),
};
}
this.Encounter = new Encounter {
Title = raw.Encounter.Title,
EncDps = TryFloat(raw.Encounter.EncDps),
};
}
private static float TryFloat(string input, float def = float.NaN) {
if (!float.TryParse(input, out var result)) {
result = def;
}
return result;
}
}
[Serializable]
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
public class Encounter {
[JsonProperty("n")]
public char N;
[JsonProperty("t")]
public char T;
public string Title;
public string Duration;
public string Damage;
public string Dps;
[JsonProperty("encdps")]
public string EncDps;
public string Hits;
[JsonProperty("crithits")]
public string CritHits;
public string Misses;
[JsonProperty("hitfailed")]
public string HitFailed;
public string Swings;
public string Healed;
[JsonProperty("enchps")]
public string EncHps;
[JsonProperty("CurrentZoneName")]
public string CurrentZoneName;
public string Title { get; init; }
public float EncDps { get; init; }
}
[Serializable]
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
public class Combatant {
public string Name;
public string Duration;
public string Damage;
public string Dps;
[JsonProperty("encdps")]
public string EncDps;
// seems like newtonsoft gets confused if we don't also specify this one
[JsonProperty("ENCDPS")]
public string EncDps2;
public string Hits;
[JsonProperty("crithits")]
public string CritHits;
public string Misses;
[JsonProperty("hitfailed")]
public string HitFailed;
public string Swings;
public string Healed;
[JsonProperty("enchps")]
public string EncHps;
}
public string Name { get; init; }
public float EncDps { get; init; }
}

View File

@ -52,6 +52,15 @@ public class Plugin : IDalamudPlugin {
var numPlayers = list->PartyMembers.Length;
foreach (var combatant in data.Combatants.Values) {
if (combatant.Name.EndsWith(" (YOU)")) {
var name = combatant.Name[..^6];
var nameNode = list->Pet.Name;
if (nameNode != null && nameNode->NodeText.ToString() == name) {
this.UpdateMember(list->Pet, combatant);
continue;
}
}
var idx = combatant.Name == "YOU"
? 0
: names.IndexOf(combatant.Name);
@ -59,18 +68,21 @@ public class Plugin : IDalamudPlugin {
continue;
}
if (!float.TryParse(combatant.EncDps, out var dps)) {
dps = 0;
}
var dpsText = dps switch {
float.PositiveInfinity => "0",
float.NegativeInfinity => "0",
< 1_000 => dps.ToString("N1"),
< 1_000_000 => $"{dps / 1_000:N1}K",
_ => $"{dps / 1_000_000:N1}M",
};
list->PartyMembers[idx].Name->SetText(dpsText);
this.UpdateMember(list->PartyMembers[idx], combatant);
}
}
private unsafe void UpdateMember(AddonPartyList.PartyListMemberStruct member, Combatant combatant) {
var dpsText = combatant.EncDps switch {
float.NaN => "?",
float.PositiveInfinity => "0",
float.NegativeInfinity => "0",
< 1_000 => combatant.EncDps.ToString("N1"),
< 1_000_000 => $"{combatant.EncDps / 1_000:N1}K",
< 1_000_000_000 => $"{combatant.EncDps / 1_000_000:N1}M",
_ => combatant.EncDps.ToString("N1"),
};
member.Name->SetText(dpsText);
}
}

92
RawCombatData.cs Normal file
View File

@ -0,0 +1,92 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace PartyDamage;
[Serializable]
public class RawCombatData {
public RawEncounter Encounter;
[JsonProperty("Combatant")]
public Dictionary<string, RawCombatant> Combatants;
}
[Serializable]
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
public class RawEncounter {
[JsonProperty("n")]
public char N;
[JsonProperty("t")]
public char T;
public string Title;
public string Duration;
public string Damage;
public string Dps;
[JsonProperty("encdps")]
public string EncDps;
[JsonProperty("ENCDPS")]
public string EncDps2;
public string Hits;
[JsonProperty("crithits")]
public string CritHits;
public string Misses;
[JsonProperty("hitfailed")]
public string HitFailed;
public string Swings;
public string Healed;
[JsonProperty("enchps")]
public string EncHps;
[JsonProperty("CurrentZoneName")]
public string CurrentZoneName;
}
[Serializable]
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
public class RawCombatant {
public string Name;
public string Duration;
public string Damage;
public string Dps;
[JsonProperty("encdps")]
public string EncDps;
// seems like newtonsoft gets confused if we don't also specify this one
[JsonProperty("ENCDPS")]
public string EncDps2;
public string Hits;
[JsonProperty("crithits")]
public string CritHits;
public string Misses;
[JsonProperty("hitfailed")]
public string HitFailed;
public string Swings;
public string Healed;
[JsonProperty("enchps")]
public string EncHps;
}