Statistics view
This commit is contained in:
parent
c5d3c90b85
commit
4bd37bdefd
@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<LangVersion>9.0</LangVersion>
|
<LangVersion>9.0</LangVersion>
|
||||||
<Version>1.4.0.0</Version>
|
<Version>1.5.0.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@ -29,6 +29,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Pal.Common\Pal.Common.csproj" />
|
||||||
<ProjectReference Include="..\vendor\ECommons\ECommons\ECommons.csproj" />
|
<ProjectReference Include="..\vendor\ECommons\ECommons\ECommons.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -7,7 +7,9 @@ using Dalamud.Plugin;
|
|||||||
using ECommons;
|
using ECommons;
|
||||||
using ECommons.Schedulers;
|
using ECommons.Schedulers;
|
||||||
using ECommons.SplatoonAPI;
|
using ECommons.SplatoonAPI;
|
||||||
|
using Grpc.Core;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
using Pal.Client.Windows;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -63,6 +65,12 @@ namespace Pal.Client
|
|||||||
Service.WindowSystem.AddWindow(configWindow);
|
Service.WindowSystem.AddWindow(configWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var statisticsWindow = pluginInterface.Create<StatisticsWindow>();
|
||||||
|
if (statisticsWindow is not null)
|
||||||
|
{
|
||||||
|
Service.WindowSystem.AddWindow(statisticsWindow);
|
||||||
|
}
|
||||||
|
|
||||||
pluginInterface.UiBuilder.Draw += Service.WindowSystem.Draw;
|
pluginInterface.UiBuilder.Draw += Service.WindowSystem.Draw;
|
||||||
pluginInterface.UiBuilder.OpenConfigUi += OnOpenConfigUi;
|
pluginInterface.UiBuilder.OpenConfigUi += OnOpenConfigUi;
|
||||||
Service.Framework.Update += OnFrameworkUpdate;
|
Service.Framework.Update += OnFrameworkUpdate;
|
||||||
@ -93,7 +101,16 @@ namespace Pal.Client
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (arguments)
|
||||||
|
{
|
||||||
|
case "stats":
|
||||||
|
Task.Run(async () => await FetchFloorStatistics());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
Service.WindowSystem.GetWindow<ConfigWindow>()?.Toggle();
|
Service.WindowSystem.GetWindow<ConfigWindow>()?.Toggle();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IDisposable Support
|
#region IDisposable Support
|
||||||
@ -341,6 +358,38 @@ namespace Pal.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task FetchFloorStatistics()
|
||||||
|
{
|
||||||
|
if (Service.Configuration.Mode != Configuration.EMode.Online)
|
||||||
|
{
|
||||||
|
Service.Chat.Print($"[Palace Pal] You can view statistics for the floor you're currently on by opening the 'Debug' tab in the configuration window.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var (success, floorStatistics) = await Service.RemoteApi.FetchStatistics();
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
var statisticsWindow = Service.WindowSystem.GetWindow<StatisticsWindow>();
|
||||||
|
statisticsWindow.SetFloorData(floorStatistics);
|
||||||
|
statisticsWindow.IsOpen = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Service.Chat.PrintError("[Palace Pal] Unable to fetch statistics.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RpcException e) when (e.StatusCode == StatusCode.PermissionDenied)
|
||||||
|
{
|
||||||
|
Service.Chat.Print($"[Palace Pal] You can view statistics for the floor you're currently on by opening the 'Debug' tab in the configuration window.");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Service.Chat.PrintError($"[Palace Pal] {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleRemoteDownloads()
|
private void HandleRemoteDownloads()
|
||||||
{
|
{
|
||||||
while (_remoteDownloads.TryDequeue(out var download))
|
while (_remoteDownloads.TryDequeue(out var download))
|
||||||
|
@ -20,8 +20,7 @@ namespace Pal.Client
|
|||||||
private const string remoteUrl = "https://pal.μ.tv";
|
private const string remoteUrl = "https://pal.μ.tv";
|
||||||
#endif
|
#endif
|
||||||
private GrpcChannel _channel;
|
private GrpcChannel _channel;
|
||||||
private string _authToken;
|
private LoginReply _lastLoginReply;
|
||||||
private DateTime _tokenExpiresAt;
|
|
||||||
|
|
||||||
private async Task<bool> Connect(CancellationToken cancellationToken, bool retry = true)
|
private async Task<bool> Connect(CancellationToken cancellationToken, bool retry = true)
|
||||||
{
|
{
|
||||||
@ -67,18 +66,12 @@ namespace Pal.Client
|
|||||||
if (string.IsNullOrEmpty(accountId))
|
if (string.IsNullOrEmpty(accountId))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_authToken) || _tokenExpiresAt < DateTime.Now)
|
if (_lastLoginReply == null || string.IsNullOrEmpty(_lastLoginReply.AuthToken) || _lastLoginReply.ExpiresAt.ToDateTime().ToLocalTime() < DateTime.Now)
|
||||||
{
|
{
|
||||||
var loginReply = await accountClient.LoginAsync(new LoginRequest { AccountId = accountId }, deadline: DateTime.UtcNow.AddSeconds(10), cancellationToken: cancellationToken);
|
_lastLoginReply = await accountClient.LoginAsync(new LoginRequest { AccountId = accountId }, deadline: DateTime.UtcNow.AddSeconds(10), cancellationToken: cancellationToken);
|
||||||
if (loginReply.Success)
|
if (!_lastLoginReply.Success)
|
||||||
{
|
{
|
||||||
_authToken = loginReply.AuthToken;
|
if (_lastLoginReply.Error == LoginError.InvalidAccountId)
|
||||||
_tokenExpiresAt = loginReply.ExpiresAt.ToDateTime().ToLocalTime();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_authToken = null;
|
|
||||||
if (loginReply.Error == LoginError.InvalidAccountId)
|
|
||||||
{
|
{
|
||||||
accountId = null;
|
accountId = null;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@ -95,7 +88,7 @@ namespace Pal.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return !string.IsNullOrEmpty(_authToken);
|
return !string.IsNullOrEmpty(_lastLoginReply?.AuthToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> VerifyConnection(CancellationToken cancellationToken = default)
|
public async Task<string> VerifyConnection(CancellationToken cancellationToken = default)
|
||||||
@ -142,9 +135,19 @@ namespace Pal.Client
|
|||||||
return uploadReply.Success;
|
return uploadReply.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<(bool, List<FloorStatistics>)> FetchStatistics(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (!await Connect(cancellationToken))
|
||||||
|
return new(false, new List<FloorStatistics>());
|
||||||
|
|
||||||
|
var palaceClient = new PalaceService.PalaceServiceClient(_channel);
|
||||||
|
var statisticsReply = await palaceClient.FetchStatisticsAsync(new StatisticsRequest(), headers: AuthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(30), cancellationToken: cancellationToken);
|
||||||
|
return (statisticsReply.Success, statisticsReply.FloorStatistics.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
private Metadata AuthorizedHeaders() => new Metadata
|
private Metadata AuthorizedHeaders() => new Metadata
|
||||||
{
|
{
|
||||||
{ "Authorization", $"Bearer {_authToken}" },
|
{ "Authorization", $"Bearer {_lastLoginReply?.AuthToken}" },
|
||||||
};
|
};
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -4,7 +4,7 @@ using ECommons;
|
|||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Pal.Client
|
namespace Pal.Client.Windows
|
||||||
{
|
{
|
||||||
internal class AgreementWindow : Window
|
internal class AgreementWindow : Window
|
||||||
{
|
{
|
@ -8,7 +8,7 @@ using System.Linq;
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Pal.Client
|
namespace Pal.Client.Windows
|
||||||
{
|
{
|
||||||
internal class ConfigWindow : Window
|
internal class ConfigWindow : Window
|
||||||
{
|
{
|
84
Pal.Client/Windows/StatisticsWindow.cs
Normal file
84
Pal.Client/Windows/StatisticsWindow.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
using ImGuiNET;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
using Pal.Common;
|
||||||
|
using Palace;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Pal.Client.Windows
|
||||||
|
{
|
||||||
|
internal class StatisticsWindow : Window
|
||||||
|
{
|
||||||
|
private SortedDictionary<ETerritoryType, TerritoryStatistics> _territoryStatistics = new();
|
||||||
|
|
||||||
|
public StatisticsWindow() : base("Palace Pal - Statistics###PalacePalStats")
|
||||||
|
{
|
||||||
|
Size = new Vector2(500, 500);
|
||||||
|
SizeCondition = ImGuiCond.FirstUseEver;
|
||||||
|
|
||||||
|
foreach (ETerritoryType territory in typeof(ETerritoryType).GetEnumValues())
|
||||||
|
{
|
||||||
|
_territoryStatistics[territory] = new TerritoryStatistics { TerritoryName = territory.ToString() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw()
|
||||||
|
{
|
||||||
|
if (ImGui.CollapsingHeader("Discovered Traps & Coffers per Instance", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
|
{
|
||||||
|
if (ImGui.BeginTable("TrapHoardStatistics", 3, ImGuiTableFlags.Borders))
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("Instance", ImGuiTableColumnFlags.WidthFixed);
|
||||||
|
ImGui.TableSetupColumn("Traps", ImGuiTableColumnFlags.WidthFixed, 100);
|
||||||
|
ImGui.TableSetupColumn("Hoard", ImGuiTableColumnFlags.WidthFixed, 100);
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
|
||||||
|
foreach (var (territoryType, stats) in _territoryStatistics)
|
||||||
|
{
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
if (ImGui.TableNextColumn())
|
||||||
|
ImGui.Text(stats.TerritoryName);
|
||||||
|
|
||||||
|
if (ImGui.TableNextColumn())
|
||||||
|
ImGui.Text(stats.TrapCount?.ToString() ?? "-");
|
||||||
|
|
||||||
|
if (ImGui.TableNextColumn())
|
||||||
|
ImGui.Text(stats.HoardCofferCount?.ToString() ?? "-");
|
||||||
|
}
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void SetFloorData(IEnumerable<FloorStatistics> floorStatistics)
|
||||||
|
{
|
||||||
|
foreach (var territoryStatistics in _territoryStatistics.Values)
|
||||||
|
{
|
||||||
|
territoryStatistics.TrapCount = null;
|
||||||
|
territoryStatistics.HoardCofferCount = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var floor in floorStatistics)
|
||||||
|
{
|
||||||
|
if (_territoryStatistics.TryGetValue((ETerritoryType)floor.TerritoryType, out TerritoryStatistics territoryStatistics))
|
||||||
|
{
|
||||||
|
territoryStatistics.TrapCount = floor.TrapCount;
|
||||||
|
territoryStatistics.HoardCofferCount = floor.HoardCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TerritoryStatistics
|
||||||
|
{
|
||||||
|
public string TerritoryName { get; set; }
|
||||||
|
public uint? TrapCount { get; set; }
|
||||||
|
public uint? HoardCofferCount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
Pal.Common/ETerritoryType.cs
Normal file
37
Pal.Common/ETerritoryType.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
namespace Pal.Common
|
||||||
|
{
|
||||||
|
public enum ETerritoryType : ushort
|
||||||
|
{
|
||||||
|
Palace_1_10 = 561,
|
||||||
|
Palace_11_20,
|
||||||
|
Palace_21_30,
|
||||||
|
Palace_31_40,
|
||||||
|
Palace_41_50,
|
||||||
|
Palace_51_60 = 593,
|
||||||
|
Palace_61_70,
|
||||||
|
Palace_71_80,
|
||||||
|
Palace_81_90,
|
||||||
|
Palace_91_100,
|
||||||
|
Palace_101_110,
|
||||||
|
Palace_111_120,
|
||||||
|
Palace_121_130,
|
||||||
|
Palace_131_140,
|
||||||
|
Palace_141_150,
|
||||||
|
Palace_151_160,
|
||||||
|
Palace_161_170,
|
||||||
|
Palace_171_180,
|
||||||
|
Palace_181_190,
|
||||||
|
Palace_191_200,
|
||||||
|
|
||||||
|
HeavenOnHigh_1_10 = 770,
|
||||||
|
HeavenOnHigh_11_20,
|
||||||
|
HeavenOnHigh_21_30,
|
||||||
|
HeavenOnHigh_31_40,
|
||||||
|
HeavenOnHigh_41_50,
|
||||||
|
HeavenOnHigh_51_60,
|
||||||
|
HeavenOnHigh_61_70 = 782,
|
||||||
|
HeavenOnHigh_71_80,
|
||||||
|
HeavenOnHigh_81_90,
|
||||||
|
HeavenOnHigh_91_100
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ package palace;
|
|||||||
service PalaceService {
|
service PalaceService {
|
||||||
rpc DownloadFloors(DownloadFloorsRequest) returns (DownloadFloorsReply);
|
rpc DownloadFloors(DownloadFloorsRequest) returns (DownloadFloorsReply);
|
||||||
rpc UploadFloors(UploadFloorsRequest) returns (UploadFloorsReply);
|
rpc UploadFloors(UploadFloorsRequest) returns (UploadFloorsReply);
|
||||||
|
rpc FetchStatistics(StatisticsRequest) returns (StatisticsReply);
|
||||||
}
|
}
|
||||||
|
|
||||||
message DownloadFloorsRequest {
|
message DownloadFloorsRequest {
|
||||||
@ -25,6 +26,20 @@ message UploadFloorsReply {
|
|||||||
bool success = 1;
|
bool success = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message StatisticsRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message StatisticsReply {
|
||||||
|
bool success = 1;
|
||||||
|
repeated FloorStatistics floorStatistics = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FloorStatistics {
|
||||||
|
uint32 territoryType = 1;
|
||||||
|
uint32 trapCount = 2;
|
||||||
|
uint32 hoardCount = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message PalaceObject {
|
message PalaceObject {
|
||||||
ObjectType type = 1;
|
ObjectType type = 1;
|
||||||
float x = 2;
|
float x = 2;
|
||||||
|
Loading…
Reference in New Issue
Block a user