Push to influx when logging out

master v0.11
Liza 2024-03-10 17:21:41 +01:00
parent b8fa10500e
commit 959a66bd24
Signed by: liza
GPG Key ID: 7199F8D727D55F67
9 changed files with 111 additions and 112 deletions

View File

@ -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<Addon>(115, s => s.Text, pluginLog)
?? throw new Exception($"Unable to resolve {nameof(LogoutToTitleScreen)}");
LogoutAndExitGame = dataManager.GetString<Addon>(116, s => s.Text, pluginLog)
?? throw new Exception($"Unable to resolve {nameof(LogoutAndExitGame)}");
}
public string LogoutToTitleScreen { get; }
public string LogoutAndExitGame { get; }
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework> <TargetFramework>net7.0-windows</TargetFramework>
<Version>0.10</Version> <Version>0.11</Version>
<LangVersion>11.0</LangVersion> <LangVersion>11.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@ -24,7 +24,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.12"/> <PackageReference Include="DalamudPackager" Version="2.1.12"/>
<PackageReference Include="InfluxDB.Client" Version="4.13.0"/> <PackageReference Include="InfluxDB.Client" Version="4.14.0" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="8.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -7,7 +7,6 @@ using Influx.AllaganTools;
using Influx.LocalStatistics; using Influx.LocalStatistics;
using InfluxDB.Client; using InfluxDB.Client;
using InfluxDB.Client.Api.Domain; using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Core;
using InfluxDB.Client.Writes; using InfluxDB.Client.Writes;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using GrandCompany = FFXIVClientStructs.FFXIV.Client.UI.Agent.GrandCompany; using GrandCompany = FFXIVClientStructs.FFXIV.Client.UI.Agent.GrandCompany;
@ -136,7 +135,7 @@ internal sealed class InfluxStatisticsClient : IDisposable
values, values,
_configuration.Server.Bucket, _configuration.Server.Organization); _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) catch (Exception e)
{ {

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Timers; using System.Timers;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Plugin; using Dalamud.Plugin;
@ -17,12 +18,14 @@ using LLib;
namespace Influx; namespace Influx;
[SuppressMessage("ReSharper", "UnusedType.Global")] [SuppressMessage("ReSharper", "UnusedType.Global")]
public class InfluxPlugin : IDalamudPlugin public sealed class InfluxPlugin : IDalamudPlugin
{ {
private readonly object _lock = new();
private readonly DalamudPluginInterface _pluginInterface; private readonly DalamudPluginInterface _pluginInterface;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly IClientState _clientState; private readonly IClientState _clientState;
private readonly ICommandManager _commandManager; private readonly ICommandManager _commandManager;
private readonly ICondition _condition;
private readonly IPluginLog _pluginLog; private readonly IPluginLog _pluginLog;
private readonly AllaganToolsIpc _allaganToolsIpc; private readonly AllaganToolsIpc _allaganToolsIpc;
private readonly SubmarineTrackerIpc _submarineTrackerIpc; private readonly SubmarineTrackerIpc _submarineTrackerIpc;
@ -36,12 +39,13 @@ public class InfluxPlugin : IDalamudPlugin
public InfluxPlugin(DalamudPluginInterface pluginInterface, IClientState clientState, IPluginLog pluginLog, public InfluxPlugin(DalamudPluginInterface pluginInterface, IClientState clientState, IPluginLog pluginLog,
ICommandManager commandManager, IChatGui chatGui, IDataManager dataManager, IFramework framework, ICommandManager commandManager, IChatGui chatGui, IDataManager dataManager, IFramework framework,
IAddonLifecycle addonLifecycle, IGameGui gameGui) IAddonLifecycle addonLifecycle, IGameGui gameGui, ICondition condition)
{ {
_pluginInterface = pluginInterface; _pluginInterface = pluginInterface;
_configuration = LoadConfig(); _configuration = LoadConfig();
_clientState = clientState; _clientState = clientState;
_commandManager = commandManager; _commandManager = commandManager;
_condition = condition;
_pluginLog = pluginLog; _pluginLog = pluginLog;
DalamudReflector dalamudReflector = new DalamudReflector(pluginInterface, framework, pluginLog); DalamudReflector dalamudReflector = new DalamudReflector(pluginInterface, framework, pluginLog);
_allaganToolsIpc = new AllaganToolsIpc(pluginInterface, chatGui, dalamudReflector, 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.Draw += _windowSystem.Draw;
_pluginInterface.UiBuilder.OpenConfigUi += _configurationWindow.Toggle; _pluginInterface.UiBuilder.OpenConfigUi += _configurationWindow.Toggle;
_condition.ConditionChange += UpdateOnLogout;
} }
private Configuration LoadConfig() private Configuration LoadConfig()
@ -94,62 +99,91 @@ public class InfluxPlugin : IDalamudPlugin
private void UpdateStatistics() private void UpdateStatistics()
{ {
if (!_clientState.IsLoggedIn || lock (_lock)
_configuration.IncludedCharacters.All(x => x.LocalContentId != _clientState.LocalContentId))
return;
try
{ {
var currencies = _allaganToolsIpc.CountCurrencies(); if (!_clientState.IsLoggedIn ||
var characters = currencies.Keys.ToList(); _configuration.IncludedCharacters.All(x => x.LocalContentId != _clientState.LocalContentId))
if (characters.Count == 0)
return;
Dictionary<string, IReadOnlyList<SortingResult>> inventoryItems =
_configuration.IncludedInventoryFilters.Select(c => c.Name)
.Distinct()
.ToDictionary(c => c, c =>
{
var filter = _allaganToolsIpc.GetFilter(c);
if (filter == null)
return new List<SortingResult>();
return filter.GenerateFilteredList();
});
var update = new StatisticsUpdate
{ {
Currencies = currencies _pluginLog.Verbose("Influx: not logged in or not enabled for this character");
.Where(x => _configuration.IncludedCharacters.Any(y => return;
y.LocalContentId == x.Key.CharacterId || }
y.LocalContentId == x.Key.OwnerId ||
characters.Any(z => y.LocalContentId == z.CharacterId && z.FreeCompanyId == x.Key.CharacterId))) try
.ToDictionary(x => x.Key, x => x.Value), {
InventoryItems = inventoryItems, var currencies = _allaganToolsIpc.CountCurrencies();
Submarines = _submarineTrackerIpc.GetSubmarineStats(characters), var characters = currencies.Keys.ToList();
LocalStats = _localStatsCalculator.GetAllCharacterStats() if (characters.Count == 0)
.Where(x => characters.Any(y => y.CharacterId == x.Key)) {
.ToDictionary(x => characters.First(y => y.CharacterId == x.Key), x => x.Value) _pluginLog.Warning("Found 0 AllaganTools characters");
.Where(x => _configuration.IncludedCharacters.Any(y => return;
y.LocalContentId == x.Key.CharacterId || }
y.LocalContentId == x.Key.OwnerId ||
characters.Any(z => y.LocalContentId == z.CharacterId && z.FreeCompanyId == x.Key.CharacterId))) Dictionary<string, IReadOnlyList<SortingResult>> inventoryItems =
.ToDictionary(x => x.Key, x => x.Value), _configuration.IncludedInventoryFilters.Select(c => c.Name)
FcStats = _fcStatsCalculator.GetAllFcStats() .Distinct()
.Where(x => characters.Any(y => y.FreeCompanyId == x.Key)) .ToDictionary(c => c, c =>
.ToDictionary(x => x.Key, x => x.Value), {
}; var filter = _allaganToolsIpc.GetFilter(c);
_statisticsWindow.OnStatisticsUpdate(update); if (filter == null)
_influxStatisticsClient.OnStatisticsUpdate(update); return new List<SortingResult>();
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() public void Dispose()
{ {
_condition.ConditionChange -= UpdateOnLogout;
_pluginInterface.UiBuilder.OpenConfigUi -= _configurationWindow.Toggle; _pluginInterface.UiBuilder.OpenConfigUi -= _configurationWindow.Toggle;
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw; _pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
_timer.Stop(); _timer.Stop();

View File

@ -1,17 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
using Dalamud.Memory;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Client.UI;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -33,7 +30,6 @@ internal sealed class LocalStatsCalculator : IDisposable
private readonly IClientState _clientState; private readonly IClientState _clientState;
private readonly IAddonLifecycle _addonLifecycle; private readonly IAddonLifecycle _addonLifecycle;
private readonly IPluginLog _pluginLog; private readonly IPluginLog _pluginLog;
private readonly GameStrings _gameStrings;
private readonly Dictionary<ulong, LocalStats> _cache = new(); private readonly Dictionary<ulong, LocalStats> _cache = new();
private IReadOnlyList<QuestInfo>? _gridaniaStart; private IReadOnlyList<QuestInfo>? _gridaniaStart;
@ -53,11 +49,9 @@ internal sealed class LocalStatsCalculator : IDisposable
_clientState = clientState; _clientState = clientState;
_addonLifecycle = addonLifecycle; _addonLifecycle = addonLifecycle;
_pluginLog = pluginLog; _pluginLog = pluginLog;
_gameStrings = new GameStrings(dataManager, pluginLog);
_clientState.Login += UpdateStatistics; _clientState.Login += UpdateStatistics;
_clientState.TerritoryChanged += UpdateStatistics; _clientState.TerritoryChanged += UpdateStatistics;
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", UpdateStatisticsLogout);
_addonLifecycle.RegisterListener(AddonEvent.PreSetup, "JournalAccept", UpdateStatistics); _addonLifecycle.RegisterListener(AddonEvent.PreSetup, "JournalAccept", UpdateStatistics);
Task.Run(() => Task.Run(() =>
@ -154,20 +148,12 @@ internal sealed class LocalStatsCalculator : IDisposable
public void Dispose() public void Dispose()
{ {
_addonLifecycle.UnregisterListener(AddonEvent.PreSetup, "JournalAccept", UpdateStatistics); _addonLifecycle.UnregisterListener(AddonEvent.PreSetup, "JournalAccept", UpdateStatistics);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectYesno", UpdateStatisticsLogout);
_clientState.Login -= UpdateStatistics; _clientState.Login -= UpdateStatistics;
} }
private void UpdateStatistics(ushort territoryType) => UpdateStatistics(); private void UpdateStatistics(ushort territoryType) => UpdateStatistics();
private unsafe void UpdateStatisticsLogout(AddonEvent type, AddonArgs args) public void UpdateStatisticsLogout() => UpdateStatistics();
{
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();
}
private void UpdateStatistics(AddonEvent type, AddonArgs args) => UpdateStatistics(); private void UpdateStatistics(AddonEvent type, AddonArgs args) => UpdateStatistics();

View File

@ -2,7 +2,7 @@
namespace Influx.LocalStatistics; namespace Influx.LocalStatistics;
public class QuestInfo public sealed class QuestInfo
{ {
public required uint RowId { get; init; } public required uint RowId { get; init; }
public required string Name { get; init; } public required string Name { get; init; }

View File

@ -6,16 +6,14 @@ namespace Influx.SubmarineTracker;
public sealed class FcSubmarines public sealed class FcSubmarines
{ {
private readonly object _delegate;
public FcSubmarines(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<object>() .Cast<object>()
.Select(x => new Submarine(x)) .Select(x => new Submarine(x))
.ToList(); .ToList()
.AsReadOnly();
} }
public List<Submarine> Submarines { get; } public IList<Submarine> Submarines { get; }
} }

View File

@ -101,7 +101,7 @@ internal sealed class ConfigurationWindow : Window
if (!tabItem) if (!tabItem)
return; 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 ?? "??"; string worldName = _clientState.LocalPlayer?.HomeWorld.GameData?.Name ?? "??";
ImGui.TextWrapped( ImGui.TextWrapped(

View File

@ -10,19 +10,25 @@
}, },
"InfluxDB.Client": { "InfluxDB.Client": {
"type": "Direct", "type": "Direct",
"requested": "[4.13.0, )", "requested": "[4.14.0, )",
"resolved": "4.13.0", "resolved": "4.14.0",
"contentHash": "2kDPC//sbSjm6R8lxqJrufNfF1AMhmeVw7dBnrOsMQjjxvaPrWFkITWIlL8AVtg5TdTqah9APp1laaJye6ebFg==", "contentHash": "X42YEtBon4thG3qsbRWxO6VAadnX4CBn1xLhNYZGNizUMUboyut6VlRqa5BGiU1pHe4MCP+cds9rD4nWGB7vsQ==",
"dependencies": { "dependencies": {
"InfluxDB.Client.Core": "4.13.0", "InfluxDB.Client.Core": "4.14.0",
"JsonSubTypes": "2.0.1", "JsonSubTypes": "2.0.1",
"Microsoft.Extensions.ObjectPool": "7.0.9", "Microsoft.Extensions.ObjectPool": "7.0.13",
"Microsoft.Net.Http.Headers": "2.2.8", "Microsoft.Net.Http.Headers": "2.2.8",
"System.Collections.Immutable": "6.0.0", "System.Collections.Immutable": "6.0.0",
"System.Configuration.ConfigurationManager": "6.0.1", "System.Configuration.ConfigurationManager": "6.0.1",
"System.Reactive": "6.0.0" "System.Reactive": "6.0.0"
} }
}, },
"Microsoft.Extensions.ObjectPool": {
"type": "Direct",
"requested": "[8.0.2, )",
"resolved": "8.0.2",
"contentHash": "LA7lDy048CVjGCwsPqRFVwH8vl5ooHmSFji13Oczw+mOnGhqenWXttkWcJ5dhIR0bhayZrQz4BaSPEVtE8Tt0A=="
},
"CsvHelper": { "CsvHelper": {
"type": "Transitive", "type": "Transitive",
"resolved": "30.0.1", "resolved": "30.0.1",
@ -30,13 +36,13 @@
}, },
"InfluxDB.Client.Core": { "InfluxDB.Client.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.13.0", "resolved": "4.14.0",
"contentHash": "SS6kVhUuQTjpbCBn6ULgXz/tLSttZhMEhmr0Vxk3vnvtlce4mYjX48NLk8QHWdUEyTL195AGrSyZTqYaDTZrgA==", "contentHash": "PtySdJE39Tv1T8p9SSpJve0Vm2gBzLdsHRL/weA97fEkeMip6Iw6zdgvb4ANWJ0MbYbprQQkSaZj2e4pTJpO6Q==",
"dependencies": { "dependencies": {
"CsvHelper": "30.0.1", "CsvHelper": "30.0.1",
"Newtonsoft.Json": "13.0.3", "Newtonsoft.Json": "13.0.3",
"NodaTime": "3.1.9", "NodaTime": "3.1.9",
"NodaTime.Serialization.JsonNet": "3.0.1", "NodaTime.Serialization.JsonNet": "3.1.0",
"RestSharp": "110.1.0" "RestSharp": "110.1.0"
} }
}, },
@ -48,11 +54,6 @@
"Newtonsoft.Json": "13.0.1" "Newtonsoft.Json": "13.0.1"
} }
}, },
"Microsoft.Extensions.ObjectPool": {
"type": "Transitive",
"resolved": "7.0.9",
"contentHash": "fFYlvFV8gle6IJ7Z0C3IydLfrzruL82pbBmn7oGsPK0zPtyN4pk2uX242ATOKbodZlRqLMAH6RE5wkRMCbkxug=="
},
"Microsoft.Extensions.Primitives": { "Microsoft.Extensions.Primitives": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.2.0", "resolved": "2.2.0",
@ -91,10 +92,10 @@
}, },
"NodaTime.Serialization.JsonNet": { "NodaTime.Serialization.JsonNet": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.1", "resolved": "3.1.0",
"contentHash": "bmw+ElaOr21HZQQVYWZKgqs0QpSb/rJcJxem3Ok6YWAdenqOi0PS2hIkvlh+QJfsl2X3VJcla9Rhya/N3JnweA==", "contentHash": "eEr9lXUz50TYr4rpeJG4TDAABkpxjIKr5mDSi/Zav8d6Njy6fH7x4ZtNwWFj0Vd+vIvEZNrHFQ4Gfy8j4BqRGg==",
"dependencies": { "dependencies": {
"Newtonsoft.Json": "13.0.1", "Newtonsoft.Json": "13.0.3",
"NodaTime": "[3.0.0, 4.0.0)" "NodaTime": "[3.0.0, 4.0.0)"
} }
}, },