From 959a66bd24f1c07d4b1b3399102d224aa405e5ec Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Sun, 10 Mar 2024 17:21:41 +0100 Subject: [PATCH] Push to influx when logging out --- Influx/GameStrings.cs | 20 --- Influx/Influx.csproj | 5 +- Influx/Influx/InfluxStatisticsClient.cs | 3 +- Influx/InfluxPlugin.cs | 132 +++++++++++------- .../LocalStatistics/LocalStatsCalculator.cs | 16 +-- Influx/LocalStatistics/QuestInfo.cs | 2 +- Influx/SubmarineTracker/FcSubmarines.cs | 10 +- Influx/Windows/ConfigurationWindow.cs | 2 +- Influx/packages.lock.json | 33 ++--- 9 files changed, 111 insertions(+), 112 deletions(-) delete mode 100644 Influx/GameStrings.cs diff --git a/Influx/GameStrings.cs b/Influx/GameStrings.cs deleted file mode 100644 index 203bda8..0000000 --- a/Influx/GameStrings.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Dalamud.Plugin.Services; -using LLib; -using Addon = Lumina.Excel.GeneratedSheets.Addon; - -namespace Influx; - -internal sealed class GameStrings -{ - public GameStrings(IDataManager dataManager, IPluginLog pluginLog) - { - LogoutToTitleScreen = dataManager.GetString(115, s => s.Text, pluginLog) - ?? throw new Exception($"Unable to resolve {nameof(LogoutToTitleScreen)}"); - LogoutAndExitGame = dataManager.GetString(116, s => s.Text, pluginLog) - ?? throw new Exception($"Unable to resolve {nameof(LogoutAndExitGame)}"); - } - - public string LogoutToTitleScreen { get; } - public string LogoutAndExitGame { get; } -} diff --git a/Influx/Influx.csproj b/Influx/Influx.csproj index 45e4966..d142850 100644 --- a/Influx/Influx.csproj +++ b/Influx/Influx.csproj @@ -1,7 +1,7 @@ net7.0-windows - 0.10 + 0.11 11.0 enable true @@ -24,7 +24,8 @@ - + + diff --git a/Influx/Influx/InfluxStatisticsClient.cs b/Influx/Influx/InfluxStatisticsClient.cs index bfdc8ff..5f9f7e3 100644 --- a/Influx/Influx/InfluxStatisticsClient.cs +++ b/Influx/Influx/InfluxStatisticsClient.cs @@ -7,7 +7,6 @@ using Influx.AllaganTools; using Influx.LocalStatistics; using InfluxDB.Client; using InfluxDB.Client.Api.Domain; -using InfluxDB.Client.Core; using InfluxDB.Client.Writes; using Lumina.Excel.GeneratedSheets; using GrandCompany = FFXIVClientStructs.FFXIV.Client.UI.Agent.GrandCompany; @@ -136,7 +135,7 @@ internal sealed class InfluxStatisticsClient : IDisposable values, _configuration.Server.Bucket, _configuration.Server.Organization); - //_chatGui.Print($"Influx: {values.Count} points"); + _pluginLog.Verbose($"Influx: Sent {values.Count} data points to server"); } catch (Exception e) { diff --git a/Influx/InfluxPlugin.cs b/Influx/InfluxPlugin.cs index c386931..4821a4c 100644 --- a/Influx/InfluxPlugin.cs +++ b/Influx/InfluxPlugin.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Timers; +using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.Command; using Dalamud.Interface.Windowing; using Dalamud.Plugin; @@ -17,12 +18,14 @@ using LLib; namespace Influx; [SuppressMessage("ReSharper", "UnusedType.Global")] -public class InfluxPlugin : IDalamudPlugin +public sealed class InfluxPlugin : IDalamudPlugin { + private readonly object _lock = new(); private readonly DalamudPluginInterface _pluginInterface; private readonly Configuration _configuration; private readonly IClientState _clientState; private readonly ICommandManager _commandManager; + private readonly ICondition _condition; private readonly IPluginLog _pluginLog; private readonly AllaganToolsIpc _allaganToolsIpc; private readonly SubmarineTrackerIpc _submarineTrackerIpc; @@ -36,12 +39,13 @@ public class InfluxPlugin : IDalamudPlugin public InfluxPlugin(DalamudPluginInterface pluginInterface, IClientState clientState, IPluginLog pluginLog, ICommandManager commandManager, IChatGui chatGui, IDataManager dataManager, IFramework framework, - IAddonLifecycle addonLifecycle, IGameGui gameGui) + IAddonLifecycle addonLifecycle, IGameGui gameGui, ICondition condition) { _pluginInterface = pluginInterface; _configuration = LoadConfig(); _clientState = clientState; _commandManager = commandManager; + _condition = condition; _pluginLog = pluginLog; DalamudReflector dalamudReflector = new DalamudReflector(pluginInterface, framework, pluginLog); _allaganToolsIpc = new AllaganToolsIpc(pluginInterface, chatGui, dalamudReflector, framework, _pluginLog); @@ -69,6 +73,7 @@ public class InfluxPlugin : IDalamudPlugin _pluginInterface.UiBuilder.Draw += _windowSystem.Draw; _pluginInterface.UiBuilder.OpenConfigUi += _configurationWindow.Toggle; + _condition.ConditionChange += UpdateOnLogout; } private Configuration LoadConfig() @@ -94,62 +99,91 @@ public class InfluxPlugin : IDalamudPlugin private void UpdateStatistics() { - if (!_clientState.IsLoggedIn || - _configuration.IncludedCharacters.All(x => x.LocalContentId != _clientState.LocalContentId)) - return; - - try + lock (_lock) { - var currencies = _allaganToolsIpc.CountCurrencies(); - var characters = currencies.Keys.ToList(); - if (characters.Count == 0) - return; - - Dictionary> inventoryItems = - _configuration.IncludedInventoryFilters.Select(c => c.Name) - .Distinct() - .ToDictionary(c => c, c => - { - var filter = _allaganToolsIpc.GetFilter(c); - if (filter == null) - return new List(); - - return filter.GenerateFilteredList(); - }); - - var update = new StatisticsUpdate + if (!_clientState.IsLoggedIn || + _configuration.IncludedCharacters.All(x => x.LocalContentId != _clientState.LocalContentId)) { - Currencies = currencies - .Where(x => _configuration.IncludedCharacters.Any(y => - y.LocalContentId == x.Key.CharacterId || - y.LocalContentId == x.Key.OwnerId || - characters.Any(z => y.LocalContentId == z.CharacterId && z.FreeCompanyId == x.Key.CharacterId))) - .ToDictionary(x => x.Key, x => x.Value), - InventoryItems = inventoryItems, - 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) - .Where(x => _configuration.IncludedCharacters.Any(y => - y.LocalContentId == x.Key.CharacterId || - y.LocalContentId == x.Key.OwnerId || - characters.Any(z => y.LocalContentId == z.CharacterId && z.FreeCompanyId == x.Key.CharacterId))) - .ToDictionary(x => x.Key, x => x.Value), - FcStats = _fcStatsCalculator.GetAllFcStats() - .Where(x => characters.Any(y => y.FreeCompanyId == x.Key)) - .ToDictionary(x => x.Key, x => x.Value), - }; - _statisticsWindow.OnStatisticsUpdate(update); - _influxStatisticsClient.OnStatisticsUpdate(update); + _pluginLog.Verbose("Influx: not logged in or not enabled for this character"); + return; + } + + try + { + var currencies = _allaganToolsIpc.CountCurrencies(); + var characters = currencies.Keys.ToList(); + if (characters.Count == 0) + { + _pluginLog.Warning("Found 0 AllaganTools characters"); + return; + } + + Dictionary> inventoryItems = + _configuration.IncludedInventoryFilters.Select(c => c.Name) + .Distinct() + .ToDictionary(c => c, c => + { + var filter = _allaganToolsIpc.GetFilter(c); + if (filter == null) + return new List(); + + return filter.GenerateFilteredList(); + }); + + var update = new StatisticsUpdate + { + Currencies = currencies + .Where(x => _configuration.IncludedCharacters.Any(y => + y.LocalContentId == x.Key.CharacterId || + y.LocalContentId == x.Key.OwnerId || + characters.Any(z => + y.LocalContentId == z.CharacterId && z.FreeCompanyId == x.Key.CharacterId))) + .ToDictionary(x => x.Key, x => x.Value), + InventoryItems = inventoryItems, + 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) + .Where(x => _configuration.IncludedCharacters.Any(y => + y.LocalContentId == x.Key.CharacterId || + y.LocalContentId == x.Key.OwnerId || + characters.Any(z => + y.LocalContentId == z.CharacterId && z.FreeCompanyId == x.Key.CharacterId))) + .ToDictionary(x => x.Key, x => x.Value), + FcStats = _fcStatsCalculator.GetAllFcStats() + .Where(x => characters.Any(y => y.FreeCompanyId == x.Key)) + .ToDictionary(x => x.Key, x => x.Value), + }; + _statisticsWindow.OnStatisticsUpdate(update); + _influxStatisticsClient.OnStatisticsUpdate(update); + } + catch (Exception e) + { + _pluginLog.Error(e, "failed to update statistics"); + } } - catch (Exception e) + } + + private void UpdateOnLogout(ConditionFlag flag, bool value) + { + if (flag == ConditionFlag.LoggingOut && value) { - _pluginLog.Error(e, "failed to update statistics"); + try + { + _timer.Enabled = false; + _localStatsCalculator.UpdateStatisticsLogout(); + UpdateStatistics(); + } + finally + { + _timer.Enabled = true; + } } } public void Dispose() { + _condition.ConditionChange -= UpdateOnLogout; _pluginInterface.UiBuilder.OpenConfigUi -= _configurationWindow.Toggle; _pluginInterface.UiBuilder.Draw -= _windowSystem.Draw; _timer.Stop(); diff --git a/Influx/LocalStatistics/LocalStatsCalculator.cs b/Influx/LocalStatistics/LocalStatsCalculator.cs index 44a818c..6becad3 100644 --- a/Influx/LocalStatistics/LocalStatsCalculator.cs +++ b/Influx/LocalStatistics/LocalStatsCalculator.cs @@ -1,17 +1,14 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading.Tasks; using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; -using Dalamud.Memory; using Dalamud.Plugin; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.UI; -using FFXIVClientStructs.FFXIV.Client.UI; using Lumina.Excel.GeneratedSheets; using Newtonsoft.Json; @@ -33,7 +30,6 @@ internal sealed class LocalStatsCalculator : IDisposable private readonly IClientState _clientState; private readonly IAddonLifecycle _addonLifecycle; private readonly IPluginLog _pluginLog; - private readonly GameStrings _gameStrings; private readonly Dictionary _cache = new(); private IReadOnlyList? _gridaniaStart; @@ -53,11 +49,9 @@ internal sealed class LocalStatsCalculator : IDisposable _clientState = clientState; _addonLifecycle = addonLifecycle; _pluginLog = pluginLog; - _gameStrings = new GameStrings(dataManager, pluginLog); _clientState.Login += UpdateStatistics; _clientState.TerritoryChanged += UpdateStatistics; - _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", UpdateStatisticsLogout); _addonLifecycle.RegisterListener(AddonEvent.PreSetup, "JournalAccept", UpdateStatistics); Task.Run(() => @@ -154,20 +148,12 @@ internal sealed class LocalStatsCalculator : IDisposable public void Dispose() { _addonLifecycle.UnregisterListener(AddonEvent.PreSetup, "JournalAccept", UpdateStatistics); - _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectYesno", UpdateStatisticsLogout); _clientState.Login -= UpdateStatistics; } private void UpdateStatistics(ushort territoryType) => UpdateStatistics(); - private unsafe void UpdateStatisticsLogout(AddonEvent type, AddonArgs args) - { - AddonSelectYesno* addonSelectYesNo = (AddonSelectYesno*)args.Addon; - string? text = MemoryHelper.ReadSeString(&addonSelectYesNo->PromptText->NodeText)?.ToString(); - text = text?.Replace("\n", "").Replace("\r", ""); - if (text == _gameStrings.LogoutToTitleScreen || text == _gameStrings.LogoutAndExitGame) - UpdateStatistics(); - } + public void UpdateStatisticsLogout() => UpdateStatistics(); private void UpdateStatistics(AddonEvent type, AddonArgs args) => UpdateStatistics(); diff --git a/Influx/LocalStatistics/QuestInfo.cs b/Influx/LocalStatistics/QuestInfo.cs index a5766fc..f2ace6f 100644 --- a/Influx/LocalStatistics/QuestInfo.cs +++ b/Influx/LocalStatistics/QuestInfo.cs @@ -2,7 +2,7 @@ namespace Influx.LocalStatistics; -public class QuestInfo +public sealed class QuestInfo { public required uint RowId { get; init; } public required string Name { get; init; } diff --git a/Influx/SubmarineTracker/FcSubmarines.cs b/Influx/SubmarineTracker/FcSubmarines.cs index 6e5ac6e..6159d57 100644 --- a/Influx/SubmarineTracker/FcSubmarines.cs +++ b/Influx/SubmarineTracker/FcSubmarines.cs @@ -6,16 +6,14 @@ namespace Influx.SubmarineTracker; public sealed class FcSubmarines { - private readonly object _delegate; - public FcSubmarines(object @delegate) { - _delegate = @delegate; - Submarines = ((IEnumerable)_delegate.GetType().GetField("Submarines")!.GetValue(_delegate)!) + Submarines = ((IEnumerable)@delegate.GetType().GetField("Submarines")!.GetValue(@delegate)!) .Cast() .Select(x => new Submarine(x)) - .ToList(); + .ToList() + .AsReadOnly(); } - public List Submarines { get; } + public IList Submarines { get; } } diff --git a/Influx/Windows/ConfigurationWindow.cs b/Influx/Windows/ConfigurationWindow.cs index 38de3a2..618a02e 100644 --- a/Influx/Windows/ConfigurationWindow.cs +++ b/Influx/Windows/ConfigurationWindow.cs @@ -101,7 +101,7 @@ internal sealed class ConfigurationWindow : Window if (!tabItem) return; - if (_clientState is { IsLoggedIn: true, LocalContentId: > 0 }) + if (_clientState is { IsLoggedIn: true, LocalContentId: > 0, LocalPlayer.HomeWorld: not null }) { string worldName = _clientState.LocalPlayer?.HomeWorld.GameData?.Name ?? "??"; ImGui.TextWrapped( diff --git a/Influx/packages.lock.json b/Influx/packages.lock.json index 9d4aaf9..9cf869b 100644 --- a/Influx/packages.lock.json +++ b/Influx/packages.lock.json @@ -10,19 +10,25 @@ }, "InfluxDB.Client": { "type": "Direct", - "requested": "[4.13.0, )", - "resolved": "4.13.0", - "contentHash": "2kDPC//sbSjm6R8lxqJrufNfF1AMhmeVw7dBnrOsMQjjxvaPrWFkITWIlL8AVtg5TdTqah9APp1laaJye6ebFg==", + "requested": "[4.14.0, )", + "resolved": "4.14.0", + "contentHash": "X42YEtBon4thG3qsbRWxO6VAadnX4CBn1xLhNYZGNizUMUboyut6VlRqa5BGiU1pHe4MCP+cds9rD4nWGB7vsQ==", "dependencies": { - "InfluxDB.Client.Core": "4.13.0", + "InfluxDB.Client.Core": "4.14.0", "JsonSubTypes": "2.0.1", - "Microsoft.Extensions.ObjectPool": "7.0.9", + "Microsoft.Extensions.ObjectPool": "7.0.13", "Microsoft.Net.Http.Headers": "2.2.8", "System.Collections.Immutable": "6.0.0", "System.Configuration.ConfigurationManager": "6.0.1", "System.Reactive": "6.0.0" } }, + "Microsoft.Extensions.ObjectPool": { + "type": "Direct", + "requested": "[8.0.2, )", + "resolved": "8.0.2", + "contentHash": "LA7lDy048CVjGCwsPqRFVwH8vl5ooHmSFji13Oczw+mOnGhqenWXttkWcJ5dhIR0bhayZrQz4BaSPEVtE8Tt0A==" + }, "CsvHelper": { "type": "Transitive", "resolved": "30.0.1", @@ -30,13 +36,13 @@ }, "InfluxDB.Client.Core": { "type": "Transitive", - "resolved": "4.13.0", - "contentHash": "SS6kVhUuQTjpbCBn6ULgXz/tLSttZhMEhmr0Vxk3vnvtlce4mYjX48NLk8QHWdUEyTL195AGrSyZTqYaDTZrgA==", + "resolved": "4.14.0", + "contentHash": "PtySdJE39Tv1T8p9SSpJve0Vm2gBzLdsHRL/weA97fEkeMip6Iw6zdgvb4ANWJ0MbYbprQQkSaZj2e4pTJpO6Q==", "dependencies": { "CsvHelper": "30.0.1", "Newtonsoft.Json": "13.0.3", "NodaTime": "3.1.9", - "NodaTime.Serialization.JsonNet": "3.0.1", + "NodaTime.Serialization.JsonNet": "3.1.0", "RestSharp": "110.1.0" } }, @@ -48,11 +54,6 @@ "Newtonsoft.Json": "13.0.1" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "7.0.9", - "contentHash": "fFYlvFV8gle6IJ7Z0C3IydLfrzruL82pbBmn7oGsPK0zPtyN4pk2uX242ATOKbodZlRqLMAH6RE5wkRMCbkxug==" - }, "Microsoft.Extensions.Primitives": { "type": "Transitive", "resolved": "2.2.0", @@ -91,10 +92,10 @@ }, "NodaTime.Serialization.JsonNet": { "type": "Transitive", - "resolved": "3.0.1", - "contentHash": "bmw+ElaOr21HZQQVYWZKgqs0QpSb/rJcJxem3Ok6YWAdenqOi0PS2hIkvlh+QJfsl2X3VJcla9Rhya/N3JnweA==", + "resolved": "3.1.0", + "contentHash": "eEr9lXUz50TYr4rpeJG4TDAABkpxjIKr5mDSi/Zav8d6Njy6fH7x4ZtNwWFj0Vd+vIvEZNrHFQ4Gfy8j4BqRGg==", "dependencies": { - "Newtonsoft.Json": "13.0.1", + "Newtonsoft.Json": "13.0.3", "NodaTime": "[3.0.0, 4.0.0)" } },