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">
<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
<Version>0.10</Version>
<Version>0.11</Version>
<LangVersion>11.0</LangVersion>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@ -24,7 +24,8 @@
<ItemGroup>
<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>

View File

@ -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)
{

View File

@ -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<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
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<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
.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();

View File

@ -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<ulong, LocalStats> _cache = new();
private IReadOnlyList<QuestInfo>? _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();

View File

@ -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; }

View File

@ -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<object>()
.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)
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(

View File

@ -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)"
}
},