diff --git a/Influx/AllaganTools/AllaganToolsIpc.cs b/Influx/AllaganTools/AllaganToolsIpc.cs index 80af870..8fddcbc 100644 --- a/Influx/AllaganTools/AllaganToolsIpc.cs +++ b/Influx/AllaganTools/AllaganToolsIpc.cs @@ -86,6 +86,9 @@ internal sealed class AllaganToolsIpc : IDisposable return new Currencies { Gil = inv.Sum(1), + GcSealsMaelstrom = inv.Sum(20), + GcSealsTwinAdders = inv.Sum(21), + GcSealsImmortalFlames = inv.Sum(22), FcCredits = inv.Sum(80), Ventures = inv.Sum(21072), CeruleumTanks = inv.Sum(10155), diff --git a/Influx/AllaganTools/Currencies.cs b/Influx/AllaganTools/Currencies.cs index 274db81..fc05a63 100644 --- a/Influx/AllaganTools/Currencies.cs +++ b/Influx/AllaganTools/Currencies.cs @@ -3,7 +3,9 @@ namespace Influx.AllaganTools; internal struct Currencies { public long Gil { get; init; } - public long GcSeals { get; init; } + public long GcSealsMaelstrom { get; init; } + public long GcSealsTwinAdders { get; init; } + public long GcSealsImmortalFlames { get; init; } public long FcCredits { get; init; } public long Ventures { get; init; } public long CeruleumTanks { get; init; } diff --git a/Influx/Influx.csproj b/Influx/Influx.csproj index ee08837..455bd8e 100644 --- a/Influx/Influx.csproj +++ b/Influx/Influx.csproj @@ -22,8 +22,8 @@ - - + + @@ -58,10 +58,10 @@ - + - + diff --git a/Influx/Influx/InfluxStatisticsClient.cs b/Influx/Influx/InfluxStatisticsClient.cs index 78f3e99..247a5d0 100644 --- a/Influx/Influx/InfluxStatisticsClient.cs +++ b/Influx/Influx/InfluxStatisticsClient.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Dalamud.Game.Gui; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; using Influx.AllaganTools; using InfluxDB.Client; using InfluxDB.Client.Api.Domain; @@ -61,6 +62,40 @@ internal class InfluxStatisticsClient : IDisposable .Field("ceruleum_tanks", currencies.CeruleumTanks) .Field("repair_kits", currencies.RepairKits) .Timestamp(date, WritePrecision.S)); + + if (update.LocalStats.TryGetValue(character, out var localStats)) + { + values.Add(PointData.Measurement("grandcompany") + .Tag("id", character.CharacterId.ToString()) + .Tag("player_name", character.Name) + .Tag("type", character.CharacterType.ToString()) + .Field("gc", localStats.GrandCompany) + .Field("gc_rank", localStats.GcRank) + .Field("seals", (GrandCompany)localStats.GrandCompany switch + { + GrandCompany.Maelstrom => currencies.GcSealsMaelstrom, + GrandCompany.TwinAdder => currencies.GcSealsTwinAdders, + GrandCompany.ImmortalFlames => currencies.GcSealsImmortalFlames, + _ => 0, + }) + .Field("seal_cap", localStats.GcRank switch + { + 1 => 10_000, + 2 => 15_000, + 3 => 20_000, + 4 => 25_000, + 5 => 30_000, + 6 => 35_000, + 7 => 40_000, + 8 => 45_000, + 9 => 50_000, + 10 => 80_000, + 11 => 90_000, + _ => 0, + }) + .Field("squadron_unlocked", localStats?.SquadronUnlocked == true ? 1 : 0) + .Timestamp(date, WritePrecision.S)); + } } else if (character.CharacterType == CharacterType.Retainer) { diff --git a/Influx/InfluxPlugin.cs b/Influx/InfluxPlugin.cs index 48c83ec..ed6c205 100644 --- a/Influx/InfluxPlugin.cs +++ b/Influx/InfluxPlugin.cs @@ -11,6 +11,7 @@ using Dalamud.Plugin; using ECommons; using Influx.AllaganTools; using Influx.Influx; +using Influx.LocalStatistics; using Influx.SubmarineTracker; using Influx.Windows; @@ -27,6 +28,7 @@ public class InfluxPlugin : IDalamudPlugin private readonly CommandManager _commandManager; private readonly AllaganToolsIpc _allaganToolsIpc; private readonly SubmarineTrackerIpc _submarineTrackerIpc; + private readonly LocalStatsCalculator _localStatsCalculator; private readonly InfluxStatisticsClient _influxStatisticsClient; private readonly WindowSystem _windowSystem; private readonly StatisticsWindow _statisticsWindow; @@ -44,6 +46,7 @@ public class InfluxPlugin : IDalamudPlugin _commandManager = commandManager; _allaganToolsIpc = new AllaganToolsIpc(pluginInterface, chatGui, _configuration); _submarineTrackerIpc = new SubmarineTrackerIpc(chatGui); + _localStatsCalculator = new LocalStatsCalculator(pluginInterface, clientState, chatGui); _influxStatisticsClient = new InfluxStatisticsClient(chatGui, _configuration); _windowSystem = new WindowSystem(typeof(InfluxPlugin).FullName); @@ -86,6 +89,8 @@ public class InfluxPlugin : IDalamudPlugin { Currencies = currencies, Submarines = _submarineTrackerIpc.GetSubmarineStats(characters), + LocalStats = _localStatsCalculator.GetAllCharacterStats() + .ToDictionary(x => characters.First(y => y.CharacterId == x.Key), x => x.Value), }; _statisticsWindow.OnStatisticsUpdate(update); _influxStatisticsClient.OnStatisticsUpdate(update); @@ -103,6 +108,7 @@ public class InfluxPlugin : IDalamudPlugin _windowSystem.RemoveAllWindows(); _commandManager.RemoveHandler("/influx"); _influxStatisticsClient.Dispose(); + _localStatsCalculator.Dispose(); _allaganToolsIpc.Dispose(); ECommonsMain.Dispose(); diff --git a/Influx/LocalStatistics/LocalStats.cs b/Influx/LocalStatistics/LocalStats.cs new file mode 100644 index 0000000..3f79141 --- /dev/null +++ b/Influx/LocalStatistics/LocalStats.cs @@ -0,0 +1,9 @@ +namespace Influx.LocalStatistics; + +public record LocalStats +{ + public ulong ContentId { get; init; } + public byte GrandCompany { get; init; } + public byte GcRank { get; init; } + public bool SquadronUnlocked { get; init; } +} diff --git a/Influx/LocalStatistics/LocalStatsCalculator.cs b/Influx/LocalStatistics/LocalStatsCalculator.cs new file mode 100644 index 0000000..4f06965 --- /dev/null +++ b/Influx/LocalStatistics/LocalStatsCalculator.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Dalamud.Game.ClientState; +using Dalamud.Game.Gui; +using Dalamud.Logging; +using Dalamud.Plugin; +using FFXIVClientStructs.FFXIV.Client.Game; +using FFXIVClientStructs.FFXIV.Client.Game.UI; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using Newtonsoft.Json; + +namespace Influx.LocalStatistics; + +public class LocalStatsCalculator : IDisposable +{ + private readonly DalamudPluginInterface _pluginInterface; + private readonly ClientState _clientState; + private readonly ChatGui _chatGui; + private readonly Dictionary _cache = new(); + + public LocalStatsCalculator(DalamudPluginInterface pluginInterface, ClientState clientState, ChatGui chatGui) + { + _pluginInterface = pluginInterface; + _clientState = clientState; + _chatGui = chatGui; + + _clientState.Login += UpdateStatistics; + _clientState.Logout += UpdateStatistics; + _clientState.TerritoryChanged += UpdateStatistics; + + foreach (var file in _pluginInterface.ConfigDirectory.GetFiles("l.*.json")) + { + try + { + var stats = JsonConvert.DeserializeObject(File.ReadAllText(file.FullName)); + if (stats == null) + continue; + + _cache[stats.ContentId] = stats; + } + catch (Exception e) + { + PluginLog.Warning(e, $"Could not parse file {file.FullName}"); + } + } + + if (_clientState.IsLoggedIn) + UpdateStatistics(); + } + + public void Dispose() + { + _clientState.Login += UpdateStatistics; + _clientState.Logout += UpdateStatistics; + _clientState.TerritoryChanged += UpdateStatistics; + } + + private void UpdateStatistics(object? sender, EventArgs e) => UpdateStatistics(); + + private void UpdateStatistics(object? sender, ushort territoryType) => UpdateStatistics(); + + private unsafe void UpdateStatistics() + { + var localContentId = _clientState.LocalContentId; + if (localContentId == 0) + { + PluginLog.Warning("No local character id"); + return; + } + + try + { + PlayerState* playerState = PlayerState.Instance(); + if (playerState == null) + return; + + LocalStats localStats = new() + { + ContentId = localContentId, + GrandCompany = playerState->GrandCompany, + GcRank = playerState->GetGrandCompanyRank(), + SquadronUnlocked = (GrandCompany)playerState->GrandCompany switch + { + GrandCompany.Maelstrom => QuestManager.IsQuestComplete(67926), + GrandCompany.TwinAdder => QuestManager.IsQuestComplete(67925), + GrandCompany.ImmortalFlames => QuestManager.IsQuestComplete(67927), + _ => false + }, + }; + + if (_cache.TryGetValue(localContentId, out var existingStats)) + { + if (existingStats != localStats) + { + _cache[localContentId] = localStats; + File.WriteAllText( + Path.Join(_pluginInterface.GetPluginConfigDirectory(), $"l.{localContentId:X8}.json"), + JsonConvert.SerializeObject(localStats)); + } + } + else + { + _cache[localContentId] = localStats; + File.WriteAllText( + Path.Join(_pluginInterface.GetPluginConfigDirectory(), $"l.{localContentId:X8}.json"), + JsonConvert.SerializeObject(localStats)); + } + } + catch (Exception e) + { + PluginLog.Error(e, "Failed to update local stats"); + } + } + + public IReadOnlyDictionary GetAllCharacterStats() => _cache.AsReadOnly(); +} diff --git a/Influx/StatisticsUpdate.cs b/Influx/StatisticsUpdate.cs index fc8696b..74e3c4c 100644 --- a/Influx/StatisticsUpdate.cs +++ b/Influx/StatisticsUpdate.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Influx.AllaganTools; +using Influx.LocalStatistics; using Influx.SubmarineTracker; namespace Influx; @@ -8,4 +9,5 @@ internal sealed class StatisticsUpdate { public required IReadOnlyDictionary Currencies { get; init; } public required Dictionary> Submarines { get; init; } + public required Dictionary LocalStats { get; init; } }