From 76822cd50aa3e94bb9776fefe78c6449860cf674 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Thu, 24 Aug 2023 00:23:30 +0200 Subject: [PATCH] Retainer Stats --- Influx/AllaganTools/Character.cs | 5 +++ Influx/Influx/InfluxStatisticsClient.cs | 37 ++++++++++++++++++- Influx/InfluxPlugin.cs | 9 ++++- Influx/LocalStatistics/LocalStats.cs | 6 ++- .../LocalStatistics/LocalStatsCalculator.cs | 16 +++++++- 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/Influx/AllaganTools/Character.cs b/Influx/AllaganTools/Character.cs index 8d793a3..01d4e34 100644 --- a/Influx/AllaganTools/Character.cs +++ b/Influx/AllaganTools/Character.cs @@ -6,21 +6,26 @@ internal sealed class Character { private readonly object _delegate; private readonly FieldInfo _name; + private readonly FieldInfo _level; public Character(object @delegate) { _delegate = @delegate; _name = _delegate.GetType().GetField("Name")!; + _level = _delegate.GetType().GetField("Level")!; CharacterId = (ulong)_delegate.GetType().GetField("CharacterId")!.GetValue(_delegate)!; CharacterType = (CharacterType)_delegate.GetType().GetProperty("CharacterType")!.GetValue(_delegate)!; + ClassJob = (byte)_delegate.GetType().GetField("ClassJob")!.GetValue(_delegate)!; OwnerId = (ulong)_delegate.GetType().GetField("OwnerId")!.GetValue(_delegate)!; FreeCompanyId = (ulong)_delegate.GetType().GetField("FreeCompanyId")!.GetValue(_delegate)!; } public ulong CharacterId { get; } public CharacterType CharacterType { get; } + public byte ClassJob { get; } public ulong OwnerId { get; } public ulong FreeCompanyId { get; } public string Name => (string)_name.GetValue(_delegate)!; + public uint Level => (uint)_level.GetValue(_delegate)!; } diff --git a/Influx/Influx/InfluxStatisticsClient.cs b/Influx/Influx/InfluxStatisticsClient.cs index 247a5d0..8960b35 100644 --- a/Influx/Influx/InfluxStatisticsClient.cs +++ b/Influx/Influx/InfluxStatisticsClient.cs @@ -3,12 +3,15 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Dalamud.Data; using Dalamud.Game.Gui; -using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using Dalamud.Logging; using Influx.AllaganTools; using InfluxDB.Client; using InfluxDB.Client.Api.Domain; using InfluxDB.Client.Writes; +using Lumina.Excel.GeneratedSheets; +using GrandCompany = FFXIVClientStructs.FFXIV.Client.UI.Agent.GrandCompany; namespace Influx.Influx; @@ -21,13 +24,19 @@ internal class InfluxStatisticsClient : IDisposable private readonly Configuration _configuration; private readonly Mutex _mutex; private readonly bool _mutexCreated; + private readonly IReadOnlyDictionary _classJobToArrayIndex; + private readonly IReadOnlyDictionary _classJobNames; - public InfluxStatisticsClient(ChatGui chatGui, Configuration configuration) + public InfluxStatisticsClient(ChatGui chatGui, Configuration configuration, DataManager dataManager) { _influxClient = new InfluxDBClient(configuration.Server.Server, configuration.Server.Token); _chatGui = chatGui; _configuration = configuration; _mutex = new Mutex(true, MutexName, out _mutexCreated); + _classJobToArrayIndex = dataManager.GetExcelSheet()!.Where(x => x.RowId > 0) + .ToDictionary(x => (byte)x.RowId, x => (byte)x.ExpArrayIndex); + _classJobNames = dataManager.GetExcelSheet()!.Where(x => x.RowId > 0) + .ToDictionary(x => (byte)x.RowId, x => x.Abbreviation.ToString()); } public bool Enabled => _configuration.Server.Enabled; @@ -109,6 +118,30 @@ internal class InfluxStatisticsClient : IDisposable .Field("ceruleum_tanks", currencies.CeruleumTanks) .Field("repair_kits", currencies.RepairKits) .Timestamp(date, WritePrecision.S)); + + if (update.LocalStats.TryGetValue(owner, out var ownerStats) && character.ClassJob != 0) + { + values.Add(PointData.Measurement("retainer") + .Tag("id", character.CharacterId.ToString()) + .Tag("player_name", owner.Name) + .Tag("type", character.CharacterType.ToString()) + .Tag("retainer_name", character.Name) + .Tag("class", _classJobNames[character.ClassJob]) + .Field("level", character.Level) + .Field("is_max_level", character.Level == ownerStats.MaxLevel ? 1 : 0) + .Field("can_reach_max_level", + ownerStats.ClassJobLevels.Count > 0 && + ownerStats.ClassJobLevels[_classJobToArrayIndex[character.ClassJob]] == + ownerStats.MaxLevel + ? 1 + : 0) + .Field("levels_before_cap", + ownerStats.ClassJobLevels.Count > 0 + ? ownerStats.ClassJobLevels[_classJobToArrayIndex[character.ClassJob]] - + character.Level + : 0) + .Timestamp(date, WritePrecision.S)); + } } else if (character.CharacterType == CharacterType.FreeCompanyChest && validFcIds.Contains(character.CharacterId)) diff --git a/Influx/InfluxPlugin.cs b/Influx/InfluxPlugin.cs index ed6c205..12a45cd 100644 --- a/Influx/InfluxPlugin.cs +++ b/Influx/InfluxPlugin.cs @@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; +using Dalamud.Data; using Dalamud.Game.ClientState; using Dalamud.Game.Command; using Dalamud.Game.Gui; @@ -36,7 +37,7 @@ public class InfluxPlugin : IDalamudPlugin private readonly Timer _timer; public InfluxPlugin(DalamudPluginInterface pluginInterface, ClientState clientState, - CommandManager commandManager, ChatGui chatGui) + CommandManager commandManager, ChatGui chatGui, DataManager dataManager) { ECommonsMain.Init(pluginInterface, this, Module.DalamudReflector); @@ -47,7 +48,7 @@ public class InfluxPlugin : IDalamudPlugin _allaganToolsIpc = new AllaganToolsIpc(pluginInterface, chatGui, _configuration); _submarineTrackerIpc = new SubmarineTrackerIpc(chatGui); _localStatsCalculator = new LocalStatsCalculator(pluginInterface, clientState, chatGui); - _influxStatisticsClient = new InfluxStatisticsClient(chatGui, _configuration); + _influxStatisticsClient = new InfluxStatisticsClient(chatGui, _configuration, dataManager); _windowSystem = new WindowSystem(typeof(InfluxPlugin).FullName); _statisticsWindow = new StatisticsWindow(); @@ -85,11 +86,15 @@ public class InfluxPlugin : IDalamudPlugin { var currencies = _allaganToolsIpc.CountCurrencies(); var characters = currencies.Keys.ToList(); + if (characters.Count == 0) + return; + var update = new StatisticsUpdate { Currencies = currencies, Submarines = _submarineTrackerIpc.GetSubmarineStats(characters), LocalStats = _localStatsCalculator.GetAllCharacterStats() + .Where(x => characters.Any(y => y.CharacterId == x.Key)) .ToDictionary(x => characters.First(y => y.CharacterId == x.Key), x => x.Value), }; _statisticsWindow.OnStatisticsUpdate(update); diff --git a/Influx/LocalStatistics/LocalStats.cs b/Influx/LocalStatistics/LocalStats.cs index 3f79141..5a8da88 100644 --- a/Influx/LocalStatistics/LocalStats.cs +++ b/Influx/LocalStatistics/LocalStats.cs @@ -1,4 +1,6 @@ -namespace Influx.LocalStatistics; +using System.Collections.Generic; + +namespace Influx.LocalStatistics; public record LocalStats { @@ -6,4 +8,6 @@ public record LocalStats public byte GrandCompany { get; init; } public byte GcRank { get; init; } public bool SquadronUnlocked { get; init; } + public byte MaxLevel { get; init; } = 90; + public List ClassJobLevels { get; set; } = new(); } diff --git a/Influx/LocalStatistics/LocalStatsCalculator.cs b/Influx/LocalStatistics/LocalStatsCalculator.cs index 7592946..f36c895 100644 --- a/Influx/LocalStatistics/LocalStatsCalculator.cs +++ b/Influx/LocalStatistics/LocalStatsCalculator.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using Dalamud.Data; using Dalamud.Game.ClientState; using Dalamud.Game.Gui; using Dalamud.Logging; @@ -19,7 +20,10 @@ public class LocalStatsCalculator : IDisposable private readonly ChatGui _chatGui; private readonly Dictionary _cache = new(); - public LocalStatsCalculator(DalamudPluginInterface pluginInterface, ClientState clientState, ChatGui chatGui) + public LocalStatsCalculator( + DalamudPluginInterface pluginInterface, + ClientState clientState, + ChatGui chatGui) { _pluginInterface = pluginInterface; _clientState = clientState; @@ -87,6 +91,8 @@ public class LocalStatsCalculator : IDisposable GrandCompany.ImmortalFlames => QuestManager.IsQuestComplete(67927), _ => false }, + MaxLevel = playerState->MaxLevel, + ClassJobLevels = ExtractClassJobLevels(playerState), }; if (_cache.TryGetValue(localContentId, out var existingStats)) @@ -113,5 +119,13 @@ public class LocalStatsCalculator : IDisposable } } + private unsafe List ExtractClassJobLevels(PlayerState* playerState) + { + List levels = new(); + for (int i = 0; i < 30; ++i) + levels.Add(playerState->ClassJobLevelArray[i]); + return levels; + } + public IReadOnlyDictionary GetAllCharacterStats() => _cache.AsReadOnly(); }