Compare commits

..

No commits in common. "master" and "v0.15" have entirely different histories.

28 changed files with 234 additions and 281 deletions

@ -1 +1 @@
Subproject commit a63c8e7154e272374ffa03d5c801736d4229e38a Subproject commit 6f0aaa55bce6ec79fd4d72f84f21597b39e5445d

@ -1 +1 @@
Subproject commit 11fd2f06e1374e846e1aada06071da5fc7ef697a Subproject commit d238d4188e8b47b11252d75cb5e4b678b8da2756

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Ipc; using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Ipc.Exceptions; using Dalamud.Plugin.Ipc.Exceptions;
@ -22,9 +21,9 @@ internal sealed class AllaganToolsIpc : IDisposable
private ICharacterMonitor _characters; private ICharacterMonitor _characters;
private IInventoryMonitor _inventories; private IInventoryMonitor _inventories;
private IListService _lists; private IFilterService _filters;
public AllaganToolsIpc(IDalamudPluginInterface pluginInterface, IChatGui chatGui, DalamudReflector dalamudReflector, public AllaganToolsIpc(DalamudPluginInterface pluginInterface, IChatGui chatGui, DalamudReflector dalamudReflector,
IFramework framework, IPluginLog pluginLog) IFramework framework, IPluginLog pluginLog)
{ {
_chatGui = chatGui; _chatGui = chatGui;
@ -38,7 +37,7 @@ internal sealed class AllaganToolsIpc : IDisposable
_characters = new UnavailableCharacterMonitor(_pluginLog); _characters = new UnavailableCharacterMonitor(_pluginLog);
_inventories = new UnavailableInventoryMonitor(_pluginLog); _inventories = new UnavailableInventoryMonitor(_pluginLog);
_lists = new UnavailableListService(_pluginLog); _filters = new UnavailableFilterService(_pluginLog);
_initialized.Subscribe(ConfigureIpc); _initialized.Subscribe(ConfigureIpc);
@ -65,25 +64,12 @@ internal sealed class AllaganToolsIpc : IDisposable
{ {
if (_dalamudReflector.TryGetDalamudPlugin("Allagan Tools", out var it, false, true)) if (_dalamudReflector.TryGetDalamudPlugin("Allagan Tools", out var it, false, true))
{ {
var hostedPlugin = it.GetType().BaseType!; var pluginService = it.GetType().Assembly.GetType("InventoryTools.PluginService")!;
var host = hostedPlugin.GetField("host", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(it)!;
var serviceProvider = host.GetType().GetProperty("Services")!.GetValue(host)!;
var getServiceMethod = serviceProvider.GetType().GetMethod("GetService")!;
object GetService(Type t) => getServiceMethod.Invoke(serviceProvider, [t])!;
var ccl = it.GetType() _characters = new CharacterMonitor(pluginService.GetProperty("CharacterMonitor")!.GetValue(null)!);
.GetField("_service", BindingFlags.NonPublic | BindingFlags.Instance)!
.GetValue(it)!
.GetType()
.Assembly;
_characters =
new CharacterMonitor(GetService(ccl.GetType("CriticalCommonLib.Services.ICharacterMonitor")!));
_inventories = new InventoryMonitor( _inventories = new InventoryMonitor(
GetService(ccl.GetType("CriticalCommonLib.Services.IInventoryMonitor")!)); pluginService.GetProperty("InventoryMonitor")!.GetValue(null)!);
_lists = new ListService( _filters = new FilterService(pluginService.GetProperty("FilterService")!.GetValue(null)!);
GetService(it.GetType().Assembly.GetType("InventoryTools.Services.Interfaces.IListService")!),
GetService(it.GetType().Assembly.GetType("InventoryTools.Lists.ListFilterService")!));
} }
else else
{ {
@ -111,11 +97,11 @@ internal sealed class AllaganToolsIpc : IDisposable
} }
} }
public FilterResult? GetFilter(string keyOrName) public Filter? GetFilter(string keyOrName)
{ {
try try
{ {
return _lists.GetFilterByKeyOrName(keyOrName); return _filters.GetFilterByKeyOrName(keyOrName);
} }
catch (IpcError e) catch (IpcError e)
{ {
@ -126,7 +112,7 @@ internal sealed class AllaganToolsIpc : IDisposable
public Dictionary<Character, Currencies> CountCurrencies() public Dictionary<Character, Currencies> CountCurrencies()
{ {
_pluginLog.Verbose($"Updating characters with {_characters.GetType()} and {_inventories.GetType()}"); _pluginLog.Debug($"{_characters.GetType()}, {_inventories.GetType()}");
var characters = _characters.All.ToDictionary(x => x.CharacterId, x => x); var characters = _characters.All.ToDictionary(x => x.CharacterId, x => x);
return _inventories.All return _inventories.All
.Where(x => characters.ContainsKey(x.Value.CharacterId)) .Where(x => characters.ContainsKey(x.Value.CharacterId))
@ -154,7 +140,7 @@ internal sealed class AllaganToolsIpc : IDisposable
_initialized.Unsubscribe(ConfigureIpc); _initialized.Unsubscribe(ConfigureIpc);
_characters = new UnavailableCharacterMonitor(_pluginLog); _characters = new UnavailableCharacterMonitor(_pluginLog);
_inventories = new UnavailableInventoryMonitor(_pluginLog); _inventories = new UnavailableInventoryMonitor(_pluginLog);
_lists = new UnavailableListService(_pluginLog); _filters = new UnavailableFilterService(_pluginLog);
} }
private sealed class InventoryWrapper(IEnumerable<InventoryItem> items) private sealed class InventoryWrapper(IEnumerable<InventoryItem> items)

View File

@ -28,11 +28,8 @@ internal sealed class Character
public CharacterType CharacterType { get; } public CharacterType CharacterType { get; }
public byte ClassJob { get; } public byte ClassJob { get; }
public ulong OwnerId { get; } public ulong OwnerId { get; }
public ulong FreeCompanyId { get; set; } public ulong FreeCompanyId { get; }
public uint WorldId { get; } public uint WorldId { get; }
public string Name => (string)_name.GetValue(_delegate)!; public string Name => (string)_name.GetValue(_delegate)!;
public uint Level => (uint)_level.GetValue(_delegate)!; public uint Level => (uint)_level.GetValue(_delegate)!;
public override string ToString() =>
$"{nameof(Character)}[{CharacterId}, {(CharacterType == CharacterType.FreeCompanyChest ? "FC" : CharacterType)}, {Name}, {WorldId}]";
} }

View File

@ -16,9 +16,8 @@ internal sealed class CharacterMonitor : ICharacterMonitor
{ {
ArgumentNullException.ThrowIfNull(@delegate); ArgumentNullException.ThrowIfNull(@delegate);
_delegate = @delegate; _delegate = @delegate;
_getPlayerCharacters = _getPlayerCharacters = _delegate.GetType().GetMethod("GetPlayerCharacters")!;
_delegate.GetType().GetMethod("GetPlayerCharacters") ?? throw new MissingMethodException(); _allCharacters = _delegate.GetType().GetMethod("AllCharacters")!;
_allCharacters = _delegate.GetType().GetMethod("AllCharacters") ?? throw new MissingMethodException();
} }
public IEnumerable<Character> PlayerCharacters => GetCharactersInternal(_getPlayerCharacters); public IEnumerable<Character> PlayerCharacters => GetCharactersInternal(_getPlayerCharacters);

View File

@ -0,0 +1,31 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Influx.AllaganTools;
internal sealed class Filter
{
private readonly object _delegate;
private readonly MethodInfo _generateFilteredList;
public Filter(object @delegate)
{
ArgumentNullException.ThrowIfNull(@delegate);
_delegate = @delegate;
_generateFilteredList = _delegate.GetType().GetMethod("GenerateFilteredList")!;
}
public IReadOnlyList<SortingResult> GenerateFilteredList()
{
Task task = (Task)_generateFilteredList.Invoke(_delegate, new object?[] { null })!;
object result = task.GetType().GetProperty("Result")!.GetValue(task)!;
return ((IEnumerable)result.GetType().GetProperty("SortedItems")!.GetValue(result)!)
.Cast<object>()
.Select(x => new SortingResult(x))
.ToList();
}
}

View File

@ -1,29 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Influx.AllaganTools;
internal sealed class FilterResult
{
private readonly IEnumerable _searchResultList;
public FilterResult(IEnumerable searchResultList)
{
ArgumentNullException.ThrowIfNull(searchResultList);
_searchResultList = searchResultList;
}
public IReadOnlyList<SortingResult> GenerateFilteredList()
{
return _searchResultList
.Cast<object>()
.Select(x => x.GetType()
.GetField("_sortingResult", BindingFlags.Instance | BindingFlags.NonPublic)!
.GetValue(x)!)
.Select(x => new SortingResult(x))
.ToList();
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Reflection;
namespace Influx.AllaganTools;
internal sealed class FilterService : IFilterService
{
private readonly object _delegate;
private readonly MethodInfo _getFilterByKeyOrName;
public FilterService(object @delegate)
{
ArgumentNullException.ThrowIfNull(@delegate);
_delegate = @delegate;
_getFilterByKeyOrName = _delegate.GetType().GetMethod("GetFilterByKeyOrName")!;
}
public Filter? GetFilterByKeyOrName(string keyOrName)
{
var f = _getFilterByKeyOrName.Invoke(_delegate, [keyOrName]);
return f != null ? new Filter(f) : null;
}
}

View File

@ -0,0 +1,6 @@
namespace Influx.AllaganTools;
internal interface IFilterService
{
Filter? GetFilterByKeyOrName(string keyOrName);
}

View File

@ -1,6 +0,0 @@
namespace Influx.AllaganTools;
internal interface IListService
{
FilterResult? GetFilterByKeyOrName(string keyOrName);
}

View File

@ -15,7 +15,7 @@ internal sealed class Inventory
{ {
ArgumentNullException.ThrowIfNull(@delegate); ArgumentNullException.ThrowIfNull(@delegate);
_delegate = @delegate; _delegate = @delegate;
_getAllInventories = _delegate.GetType().GetMethod("GetAllInventories") ?? throw new MissingMethodException(); _getAllInventories = _delegate.GetType().GetMethod("GetAllInventories")!;
CharacterId = (ulong)_delegate.GetType().GetProperty("CharacterId")!.GetValue(_delegate)!; CharacterId = (ulong)_delegate.GetType().GetProperty("CharacterId")!.GetValue(_delegate)!;
} }

View File

@ -1,5 +1,5 @@
using System; using System;
using Dalamud.Logging; using FFXIVClientStructs.FFXIV.Client.Game;
namespace Influx.AllaganTools; namespace Influx.AllaganTools;
@ -10,7 +10,7 @@ internal sealed class InventoryItem
ArgumentNullException.ThrowIfNull(@delegate); ArgumentNullException.ThrowIfNull(@delegate);
Category = (int)@delegate.GetType().GetField("SortedCategory")!.GetValue(@delegate)!; Category = (int)@delegate.GetType().GetField("SortedCategory")!.GetValue(@delegate)!;
Container = (int)@delegate.GetType().GetField("SortedContainer")!.GetValue(@delegate)!; Container = (int)@delegate.GetType().GetField("SortedContainer")!.GetValue(@delegate)!;
ItemId = (uint)@delegate.GetType().GetProperty("ItemId")!.GetValue(@delegate)!; ItemId = (uint)@delegate.GetType().GetField("ItemId")!.GetValue(@delegate)!;
Quantity = (uint)@delegate.GetType().GetField("Quantity")!.GetValue(@delegate)!; Quantity = (uint)@delegate.GetType().GetField("Quantity")!.GetValue(@delegate)!;
} }

View File

@ -1,29 +0,0 @@
using System;
using System.Collections;
using System.Reflection;
namespace Influx.AllaganTools;
internal sealed class ListService : IListService
{
private readonly object _listService;
private readonly object _listFilterService;
private readonly MethodInfo _getListByKeyOrName;
private readonly MethodInfo _refreshList;
public ListService(object listService, object listFilterService)
{
ArgumentNullException.ThrowIfNull(listService);
_listService = listService;
_listFilterService = listFilterService;
_getListByKeyOrName =
_listService.GetType().GetMethod("GetListByKeyOrName") ?? throw new MissingMethodException();
_refreshList = _listFilterService.GetType().GetMethod("RefreshList") ?? throw new MissingMethodException();
}
public FilterResult? GetFilterByKeyOrName(string keyOrName)
{
var f = _getListByKeyOrName.Invoke(_listService, [keyOrName]);
return f != null ? new FilterResult((IEnumerable)_refreshList.Invoke(_listFilterService, [f])!) : null;
}
}

View File

@ -13,7 +13,7 @@ internal sealed class SortingResult
Quantity = (int)@delegate.GetType().GetProperty("Quantity")!.GetValue(@delegate)!; Quantity = (int)@delegate.GetType().GetProperty("Quantity")!.GetValue(@delegate)!;
var inventoryItem = @delegate.GetType().GetProperty("InventoryItem")!.GetValue(@delegate)!; var inventoryItem = @delegate.GetType().GetProperty("InventoryItem")!.GetValue(@delegate)!;
ItemId = (uint)inventoryItem.GetType().GetProperty("ItemId")!.GetValue(inventoryItem)!; ItemId = (uint)inventoryItem.GetType().GetField("ItemId")!.GetValue(inventoryItem)!;
Flags = (ItemFlags)inventoryItem.GetType().GetField("Flags")!.GetValue(inventoryItem)!; Flags = (ItemFlags)inventoryItem.GetType().GetField("Flags")!.GetValue(inventoryItem)!;
} }
@ -22,7 +22,7 @@ internal sealed class SortingResult
public ItemFlags Flags { get; } public ItemFlags Flags { get; }
public int Quantity { get; } public int Quantity { get; }
public bool IsHq => Flags.HasFlag(ItemFlags.HighQuality); public bool IsHq => Flags.HasFlag(ItemFlags.HQ);
public override string ToString() public override string ToString()
{ {

View File

@ -2,9 +2,9 @@
namespace Influx.AllaganTools; namespace Influx.AllaganTools;
internal sealed class UnavailableListService(IPluginLog pluginLog) : IListService internal sealed class UnavailableFilterService(IPluginLog pluginLog) : IFilterService
{ {
public FilterResult? GetFilterByKeyOrName(string keyOrName) public Filter? GetFilterByKeyOrName(string keyOrName)
{ {
pluginLog.Warning("Filter Service is unavailable"); pluginLog.Warning("Filter Service is unavailable");
return null; return null;

View File

@ -1,15 +1,58 @@
<Project Sdk="Dalamud.NET.Sdk/10.0.0"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Version>1.3</Version> <TargetFramework>net8.0-windows</TargetFramework>
<Version>0.15</Version>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<OutputPath>dist</OutputPath> <OutputPath>dist</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PathMap Condition="$(SolutionDir) != ''">$(SolutionDir)=X:\</PathMap>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<DebugType>portable</DebugType>
</PropertyGroup> </PropertyGroup>
<Import Project="..\LLib\LLib.targets"/> <PropertyGroup>
<Import Project="..\LLib\RenameZip.targets"/> <DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
</PropertyGroup>
<PropertyGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))'">
<DalamudLibPath>$(DALAMUD_HOME)/</DalamudLibPath>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.12"/>
<PackageReference Include="InfluxDB.Client" Version="4.14.0" /> <PackageReference Include="InfluxDB.Client" Version="4.14.0" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0-preview.1.24081.5" /> <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="8.0.3" />
</ItemGroup>
<ItemGroup>
<Reference Include="Dalamud">
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="ImGui.NET">
<HintPath>$(DalamudLibPath)ImGui.NET.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Lumina">
<HintPath>$(DalamudLibPath)Lumina.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Lumina.Excel">
<HintPath>$(DalamudLibPath)Lumina.Excel.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="FFXIVClientStructs">
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -17,4 +60,8 @@
<ProjectReference Include="..\ECommons\ECommons\ECommons.csproj" /> <ProjectReference Include="..\ECommons\ECommons\ECommons.csproj" />
<ProjectReference Include="..\LLib\LLib.csproj" /> <ProjectReference Include="..\LLib\LLib.csproj" />
</ItemGroup> </ItemGroup>
<Target Name="RenameLatestZip" AfterTargets="PackagePlugin">
<Exec Command="rename $(OutDir)$(AssemblyName)\latest.zip $(AssemblyName)-$(Version).zip"/>
</Target>
</Project> </Project>

View File

@ -216,10 +216,6 @@ internal sealed class InfluxStatisticsClient : IDisposable
{ {
foreach (var (expIndex, job) in _expToJobs) foreach (var (expIndex, job) in _expToJobs)
{ {
// last update to this char was in 6.x, so we don't have PCT/VPR data
if (localStats.ClassJobLevels.Count <= expIndex)
continue;
var level = localStats.ClassJobLevels[expIndex]; var level = localStats.ClassJobLevels[expIndex];
if (level > 0) if (level > 0)
{ {

View File

@ -22,7 +22,7 @@ namespace Influx;
internal sealed class InfluxPlugin : IDalamudPlugin internal sealed class InfluxPlugin : IDalamudPlugin
{ {
private readonly object _lock = new(); private readonly object _lock = new();
private readonly IDalamudPluginInterface _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;
@ -38,7 +38,7 @@ internal sealed class InfluxPlugin : IDalamudPlugin
private readonly ConfigurationWindow _configurationWindow; private readonly ConfigurationWindow _configurationWindow;
private readonly Timer _timer; private readonly Timer _timer;
public InfluxPlugin(IDalamudPluginInterface 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, ICondition condition) IAddonLifecycle addonLifecycle, IGameGui gameGui, ICondition condition)
{ {
@ -119,17 +119,6 @@ internal sealed class InfluxPlugin : IDalamudPlugin
return; return;
} }
foreach (Character character in characters)
{
if (character.CharacterType == CharacterType.Character && character.FreeCompanyId != default)
{
bool isFcEnabled = _configuration.IncludedCharacters
.FirstOrDefault(x => x.LocalContentId == character.CharacterId)?.IncludeFreeCompany ?? true;
if (!isFcEnabled)
character.FreeCompanyId = default;
}
}
Dictionary<string, IReadOnlyList<SortingResult>> inventoryItems = Dictionary<string, IReadOnlyList<SortingResult>> inventoryItems =
_configuration.IncludedInventoryFilters.Select(c => c.Name) _configuration.IncludedInventoryFilters.Select(c => c.Name)
.Distinct() .Distinct()
@ -176,8 +165,8 @@ internal sealed class InfluxPlugin : IDalamudPlugin
} }
} }
private IReadOnlyDictionary<Character, List<SubmarineStats>> UpdateEnabledSubs( private Dictionary<Character, List<SubmarineStats>> UpdateEnabledSubs(
IReadOnlyDictionary<Character, List<SubmarineStats>> allSubs, List<Character> characters) Dictionary<Character, List<SubmarineStats>> allSubs, List<Character> characters)
{ {
foreach (var (character, subs) in allSubs) foreach (var (character, subs) in allSubs)
{ {

View File

@ -18,7 +18,7 @@ namespace Influx.LocalStatistics;
internal sealed class FcStatsCalculator : IDisposable internal sealed class FcStatsCalculator : IDisposable
{ {
private readonly IDalamudPluginInterface _pluginInterface; private readonly DalamudPluginInterface _pluginInterface;
private readonly IClientState _clientState; private readonly IClientState _clientState;
private readonly IAddonLifecycle _addonLifecycle; private readonly IAddonLifecycle _addonLifecycle;
private readonly IGameGui _gameGui; private readonly IGameGui _gameGui;
@ -33,7 +33,7 @@ internal sealed class FcStatsCalculator : IDisposable
public FcStatsCalculator( public FcStatsCalculator(
IDalamudPlugin plugin, IDalamudPlugin plugin,
IDalamudPluginInterface pluginInterface, DalamudPluginInterface pluginInterface,
IClientState clientState, IClientState clientState,
IAddonLifecycle addonLifecycle, IAddonLifecycle addonLifecycle,
IGameGui gameGui, IGameGui gameGui,
@ -86,9 +86,9 @@ internal sealed class FcStatsCalculator : IDisposable
if (infoProxy != null) if (infoProxy != null)
{ {
var fcProxy = (InfoProxyFreeCompany*)infoProxy; var fcProxy = (InfoProxyFreeCompany*)infoProxy;
if (fcProxy->Id != 0) if (fcProxy->ID != 0)
{ {
_pluginLog.Information($"Requesting post-process, FC is {fcProxy->Id}"); _pluginLog.Information($"Requesting post-process, FC is {fcProxy->ID}");
_autoRetainerApi.RequestCharacterPostprocess(); _autoRetainerApi.RequestCharacterPostprocess();
} }
else else
@ -157,14 +157,14 @@ internal sealed class FcStatsCalculator : IDisposable
if (infoProxy != null) if (infoProxy != null)
{ {
var fcProxy = (InfoProxyFreeCompany*)infoProxy; var fcProxy = (InfoProxyFreeCompany*)infoProxy;
ulong localContentId = fcProxy->Id; ulong localContentId = fcProxy->ID;
if (localContentId != 0) if (localContentId != 0)
{ {
var atkArrays = Framework.Instance()->GetUIModule()->GetRaptureAtkModule()->AtkModule var atkArrays = Framework.Instance()->GetUiModule()->GetRaptureAtkModule()->AtkModule
.AtkArrayDataHolder; .AtkArrayDataHolder;
if (atkArrays.NumberArrayCount > 51) if (atkArrays.NumberArrayCount > 50)
{ {
var fcArrayData = atkArrays.GetNumberArrayData(51); var fcArrayData = atkArrays.GetNumberArrayData(50);
FcStats fcStats = new FcStats FcStats fcStats = new FcStats
{ {
ContentId = localContentId, ContentId = localContentId,

View File

@ -27,7 +27,7 @@ internal sealed class LocalStatsCalculator : IDisposable
private const uint JointQuest = 65781; private const uint JointQuest = 65781;
private readonly IDalamudPluginInterface _pluginInterface; private readonly DalamudPluginInterface _pluginInterface;
private readonly IClientState _clientState; private readonly IClientState _clientState;
private readonly IAddonLifecycle _addonLifecycle; private readonly IAddonLifecycle _addonLifecycle;
private readonly IPluginLog _pluginLog; private readonly IPluginLog _pluginLog;
@ -40,7 +40,7 @@ internal sealed class LocalStatsCalculator : IDisposable
public LocalStatsCalculator( public LocalStatsCalculator(
IDalamudPluginInterface pluginInterface, DalamudPluginInterface pluginInterface,
IClientState clientState, IClientState clientState,
IAddonLifecycle addonLifecycle, IAddonLifecycle addonLifecycle,
IPluginLog pluginLog, IPluginLog pluginLog,
@ -58,9 +58,11 @@ internal sealed class LocalStatsCalculator : IDisposable
Task.Run(() => Task.Run(() =>
{ {
List<QuestInfo> msq = new(); List<QuestInfo> msq = new();
foreach (var quest in dataManager.GetExcelSheet<Quest>()!.Where(x => x.JournalGenre.Row is >= 1 and <= 13)) foreach (var quest in dataManager.GetExcelSheet<Quest>()!.Where(x => x.JournalGenre.Row is >= 1 and <= 12))
{ {
var previousQuests = quest.PreviousQuest?.Select(x => x.Row).Where(x => x != 0).ToList(); var previousQuests = quest.PreviousQuest?.Select(x => x.Row).Where(x => x != 0).ToList();
if (previousQuests != null && quest.Unknown12 != 0)
previousQuests.Add(quest.Unknown12);
msq.Add(new QuestInfo msq.Add(new QuestInfo
{ {
@ -246,8 +248,8 @@ internal sealed class LocalStatsCalculator : IDisposable
private unsafe List<short> ExtractClassJobLevels(PlayerState* playerState) private unsafe List<short> ExtractClassJobLevels(PlayerState* playerState)
{ {
List<short> levels = new(); List<short> levels = new();
for (int i = 0; i < 32; ++i) for (int i = 0; i < 30; ++i)
levels.Add(playerState->ClassJobLevels[i]); levels.Add(playerState->ClassJobLevelArray[i]);
return levels; return levels;
} }

View File

@ -9,7 +9,7 @@ internal sealed class StatisticsUpdate
{ {
public required IReadOnlyDictionary<Character, Currencies> Currencies { get; init; } public required IReadOnlyDictionary<Character, Currencies> Currencies { get; init; }
public required IReadOnlyDictionary<string, IReadOnlyList<SortingResult>> InventoryItems { get; init; } public required IReadOnlyDictionary<string, IReadOnlyList<SortingResult>> InventoryItems { get; init; }
public required IReadOnlyDictionary<Character, List<SubmarineStats>> Submarines { get; init; } public required Dictionary<Character, List<SubmarineStats>> Submarines { get; init; }
public required IReadOnlyDictionary<Character, LocalStats> LocalStats { get; init; } public required Dictionary<Character, LocalStats> LocalStats { get; init; }
public required IReadOnlyDictionary<ulong, FcStats> FcStats { get; init; } public required Dictionary<ulong, FcStats> FcStats { get; init; }
} }

View File

@ -0,0 +1,21 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Influx.SubmarineTracker;
internal sealed class FcSubmarines
{
public FcSubmarines(object @delegate)
{
ArgumentNullException.ThrowIfNull(@delegate);
Submarines = ((IEnumerable)@delegate.GetType().GetField("Submarines")!.GetValue(@delegate)!)
.Cast<object>()
.Select(x => new Submarine(x))
.ToList()
.AsReadOnly();
}
public IList<Submarine> Submarines { get; }
}

View File

@ -8,11 +8,9 @@ internal sealed class Submarine
{ {
ArgumentNullException.ThrowIfNull(@delegate); ArgumentNullException.ThrowIfNull(@delegate);
Type type = @delegate.GetType(); Type type = @delegate.GetType();
FreeCompanyId = (ulong)type.GetField("FreeCompanyId")!.GetValue(@delegate)!; Name = (string)type.GetProperty("Name")!.GetValue(@delegate)!;
Name = (string)type.GetField("Name")!.GetValue(@delegate)!; Level = (ushort)type.GetProperty("Rank")!.GetValue(@delegate)!;
Level = (ushort)type.GetField("Rank")!.GetValue(@delegate)!;
Build = new Build(type.GetProperty("Build")!.GetValue(@delegate)!); Build = new Build(type.GetProperty("Build")!.GetValue(@delegate)!);
ReturnTime = (DateTime)type.GetField("ReturnTime")!.GetValue(@delegate)!;
try try
{ {
@ -30,6 +28,8 @@ internal sealed class Submarine
(uint predictedLevel, double _) = ((uint, double))type.GetMethod("PredictExpGrowth")!.Invoke(@delegate, Array.Empty<object?>())!; (uint predictedLevel, double _) = ((uint, double))type.GetMethod("PredictExpGrowth")!.Invoke(@delegate, Array.Empty<object?>())!;
PredictedLevel = (ushort)predictedLevel; PredictedLevel = (ushort)predictedLevel;
} }
ReturnTime = (DateTime)type.GetField("ReturnTime")!.GetValue(@delegate)!;
} }
catch (Exception) catch (Exception)
{ {
@ -37,7 +37,6 @@ internal sealed class Submarine
} }
} }
public ulong FreeCompanyId { get; }
public string Name { get; } public string Name { get; }
public ushort Level { get; } public ushort Level { get; }
public ushort PredictedLevel { get; } public ushort PredictedLevel { get; }

View File

@ -1,9 +1,7 @@
using System; using System.Collections;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection;
using Dalamud.Plugin; using Dalamud.Plugin;
using Influx.AllaganTools; using Influx.AllaganTools;
using LLib; using LLib;
@ -20,55 +18,49 @@ internal sealed class SubmarineTrackerIpc
} }
[SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")]
public IReadOnlyDictionary<Character, List<SubmarineStats>> GetSubmarineStats(List<Character> characters) public Dictionary<Character, List<SubmarineStats>> GetSubmarineStats(List<Character> characters)
{ {
if (_dalamudReflector.TryGetDalamudPlugin("Submarine Tracker", out IDalamudPlugin? it, false, true)) if (_dalamudReflector.TryGetDalamudPlugin("Submarine Tracker", out IDalamudPlugin? it, false, true))
{ {
var databaseCache = it.GetType() var submarineData = it.GetType().Assembly.GetType("SubmarineTracker.Data.Submarines");
.GetField("DatabaseCache", BindingFlags.Static | BindingFlags.Public)! var knownSubmarineData = submarineData!.GetField("KnownSubmarines")!;
.GetValue(null)!; return ((IEnumerable)knownSubmarineData.GetValue(null)!).Cast<object>()
var getSubmarines = databaseCache.GetType() .Select(x => new
.GetMethod("GetSubmarines", [])!; {
var knownSubmarineData = ((IEnumerable)getSubmarines.Invoke(databaseCache, [])!).Cast<object>(); OwnerId = (ulong)x.GetType().GetProperty("Key")!.GetValue(x)!,
return knownSubmarineData FcWrapper = x.GetType().GetProperty("Value")!.GetValue(x)!
.Select(x => new Submarine(x)) })
.GroupBy(x => x.FreeCompanyId) .Select(x => new
.Select(x => new SubmarineInfo( {
characters.SingleOrDefault(y => Owner = characters.FirstOrDefault(y => y.CharacterId == x.OwnerId),
y.CharacterType == CharacterType.FreeCompanyChest && y.CharacterId == x.Key), Subs = new FcSubmarines(x.FcWrapper).Submarines,
x.ToList() })
)) .Where(x => x.Owner != null)
.Select(x => new
{
x.Subs,
Fc = characters.FirstOrDefault(y => y.CharacterId == x.Owner!.FreeCompanyId)
})
.Where(x => x.Fc != null) .Where(x => x.Fc != null)
.ToDictionary(x => x.Fc!, x => x.Subs); .ToDictionary(
x => x.Fc!,
x => x.Subs.Select(y => new SubmarineStats
{
Id = x.Subs.IndexOf(y),
Name = y.Name,
WorldId = x.Fc!.WorldId,
Level = y.Level,
PredictedLevel = y.PredictedLevel,
Hull = y.Build.HullIdentifier,
Stern = y.Build.SternIdentifier,
Bow = y.Build.BowIdentifier,
Bridge = y.Build.BridgeIdentifier,
Build = y.Build.FullIdentifier,
State = y.State,
ReturnTime = y.ReturnTime,
}).ToList());
} }
else else
return new Dictionary<Character, List<SubmarineStats>>(); return new Dictionary<Character, List<SubmarineStats>>();
} }
private sealed record SubmarineInfo(Character? Fc, List<SubmarineStats> Subs)
{
public SubmarineInfo(Character? fc, List<Submarine> subs)
: this(fc, subs.Select(x => Convert(fc, subs.IndexOf(x), x)).ToList())
{
}
private static SubmarineStats Convert(Character? fc, int index, Submarine y)
{
return new SubmarineStats
{
Id = index,
Name = y.Name,
WorldId = fc?.WorldId ?? 0,
Level = y.Level,
PredictedLevel = y.PredictedLevel,
Hull = y.Build.HullIdentifier,
Stern = y.Build.SternIdentifier,
Bow = y.Build.BowIdentifier,
Bridge = y.Build.BridgeIdentifier,
Build = y.Build.FullIdentifier,
State = y.State,
ReturnTime = y.ReturnTime,
};
}
}
} }

View File

@ -14,14 +14,14 @@ namespace Influx.Windows;
internal sealed class ConfigurationWindow : Window internal sealed class ConfigurationWindow : Window
{ {
private readonly IDalamudPluginInterface _pluginInterface; private readonly DalamudPluginInterface _pluginInterface;
private readonly IClientState _clientState; private readonly IClientState _clientState;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly AllaganToolsIpc _allaganToolsIpc; private readonly AllaganToolsIpc _allaganToolsIpc;
private string[] _filterNames = []; private string[] _filterNames = Array.Empty<string>();
private int _filterIndexToAdd; private int _filterIndexToAdd;
public ConfigurationWindow(IDalamudPluginInterface pluginInterface, IClientState clientState, public ConfigurationWindow(DalamudPluginInterface pluginInterface, IClientState clientState,
Configuration configuration, AllaganToolsIpc allaganToolsIpc) Configuration configuration, AllaganToolsIpc allaganToolsIpc)
: base("Configuration###InfluxConfiguration") : base("Configuration###InfluxConfiguration")
{ {

View File

@ -24,10 +24,10 @@ internal sealed class StatisticsWindow : Window
public override void Draw() public override void Draw()
{ {
if (ImGui.BeginTable("Currencies###InfluxStatisticsCurrencies", 2)) if (ImGui.BeginTable("Currencies###InfluxStatisticsCurrencies", 4))
{ {
ImGui.TableSetupColumn("Name"); ImGui.TableSetupColumn("Name");
ImGui.TableSetupColumn($"Gil ({_rows.Sum(x => x.Gil):N0})##Gil"); ImGui.TableSetupColumn("Gil");
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
foreach (var row in _rows) foreach (var row in _rows)

View File

@ -4,21 +4,9 @@
"net8.0-windows7.0": { "net8.0-windows7.0": {
"DalamudPackager": { "DalamudPackager": {
"type": "Direct", "type": "Direct",
"requested": "[2.1.13, )", "requested": "[2.1.12, )",
"resolved": "2.1.13", "resolved": "2.1.12",
"contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ==" "contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg=="
},
"DotNet.ReproducibleBuilds": {
"type": "Direct",
"requested": "[1.1.1, )",
"resolved": "1.1.1",
"contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==",
"dependencies": {
"Microsoft.SourceLink.AzureRepos.Git": "1.1.1",
"Microsoft.SourceLink.Bitbucket.Git": "1.1.1",
"Microsoft.SourceLink.GitHub": "1.1.1",
"Microsoft.SourceLink.GitLab": "1.1.1"
}
}, },
"InfluxDB.Client": { "InfluxDB.Client": {
"type": "Direct", "type": "Direct",
@ -37,19 +25,9 @@
}, },
"Microsoft.Extensions.ObjectPool": { "Microsoft.Extensions.ObjectPool": {
"type": "Direct", "type": "Direct",
"requested": "[9.0.0-preview.1.24081.5, )", "requested": "[8.0.3, )",
"resolved": "9.0.0-preview.1.24081.5", "resolved": "8.0.3",
"contentHash": "aAR7YW+pUUdvHk3vj7GtAi71dWGDIuY9270lsmQ6lKw23zzY+r8pLP3cGNbJdlnA9VWl+S+gnIVkBCqj2ROlEg==" "contentHash": "sk/TGiccSeXUtVeBfFlWJnzp6xLlAxIW+bCHs7uVPLFPQk8vICNmu9Gc3JsKOn6fQuRkrPetQ8EHv4dCiMqhxg=="
},
"Microsoft.SourceLink.Gitea": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "KOBodmDnlWGIqZt2hT47Q69TIoGhIApDVLCyyj9TT5ct8ju16AbHYcB4XeknoHX562wO1pMS/1DfBIZK+V+sxg==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
}, },
"CsvHelper": { "CsvHelper": {
"type": "Transitive", "type": "Transitive",
@ -76,11 +54,6 @@
"Newtonsoft.Json": "13.0.1" "Newtonsoft.Json": "13.0.1"
} }
}, },
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.Extensions.Primitives": { "Microsoft.Extensions.Primitives": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.2.0", "resolved": "2.2.0",
@ -99,47 +72,6 @@
"System.Buffers": "4.5.0" "System.Buffers": "4.5.0"
} }
}, },
"Microsoft.SourceLink.AzureRepos.Git": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.SourceLink.Bitbucket.Git": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
},
"Microsoft.SourceLink.GitHub": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.SourceLink.GitLab": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.Win32.SystemEvents": { "Microsoft.Win32.SystemEvents": {
"type": "Transitive", "type": "Transitive",
"resolved": "6.0.0", "resolved": "6.0.0",
@ -263,17 +195,14 @@
"autoretainerapi": { "autoretainerapi": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"ECommons": "[2.2.0.2, )" "ECommons": "[2.1.0.7, )"
} }
}, },
"ecommons": { "ecommons": {
"type": "Project" "type": "Project"
}, },
"llib": { "llib": {
"type": "Project", "type": "Project"
"dependencies": {
"DalamudPackager": "[2.1.13, )"
}
} }
} }
} }

2
LLib

@ -1 +1 @@
Subproject commit 8d947be6784804a7cab120d596dd54e88e548efc Subproject commit 3792244261a9f5426a7916f5a6dd1966238ba84a