Compare commits

..

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

24 changed files with 207 additions and 211 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

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

@ -7,22 +7,23 @@ using System.Threading.Tasks;
namespace Influx.AllaganTools; namespace Influx.AllaganTools;
internal sealed class FilterResult internal sealed class Filter
{ {
private readonly object _delegate; private readonly object _delegate;
private readonly PropertyInfo _sortedItems; private readonly MethodInfo _generateFilteredList;
public FilterResult(object @delegate) public Filter(object @delegate)
{ {
ArgumentNullException.ThrowIfNull(@delegate); ArgumentNullException.ThrowIfNull(@delegate);
_delegate = @delegate; _delegate = @delegate;
_sortedItems = _generateFilteredList = _delegate.GetType().GetMethod("GenerateFilteredList")!;
_delegate.GetType().GetProperty("SortedItems") ?? throw new MissingMemberException();
} }
public IReadOnlyList<SortingResult> GenerateFilteredList() public IReadOnlyList<SortingResult> GenerateFilteredList()
{ {
return ((IEnumerable)_sortedItems.GetValue(_delegate)!) 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>() .Cast<object>()
.Select(x => new SortingResult(x)) .Select(x => new SortingResult(x))
.ToList(); .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,28 +0,0 @@
using System;
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(_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.2</Version> <TargetFramework>net8.0-windows</TargetFramework>
<Version>0.16</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)
{ {
@ -50,7 +50,7 @@ internal sealed class InfluxPlugin : IDalamudPlugin
_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);
_submarineTrackerIpc = new SubmarineTrackerIpc(dalamudReflector); _submarineTrackerIpc = new SubmarineTrackerIpc(dalamudReflector, chatGui, pluginLog);
_localStatsCalculator = _localStatsCalculator =
new LocalStatsCalculator(pluginInterface, clientState, addonLifecycle, pluginLog, dataManager); new LocalStatsCalculator(pluginInterface, clientState, addonLifecycle, pluginLog, dataManager);
_fcStatsCalculator = new FcStatsCalculator(this, pluginInterface, clientState, addonLifecycle, gameGui, _fcStatsCalculator = new FcStatsCalculator(this, pluginInterface, clientState, addonLifecycle, gameGui,

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

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

@ -3,8 +3,8 @@ 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 Dalamud.Plugin.Services;
using Influx.AllaganTools; using Influx.AllaganTools;
using LLib; using LLib;
@ -13,10 +13,14 @@ namespace Influx.SubmarineTracker;
internal sealed class SubmarineTrackerIpc internal sealed class SubmarineTrackerIpc
{ {
private readonly DalamudReflector _dalamudReflector; private readonly DalamudReflector _dalamudReflector;
private readonly IChatGui _chatGui;
private readonly IPluginLog _pluginLog;
public SubmarineTrackerIpc(DalamudReflector dalamudReflector) public SubmarineTrackerIpc(DalamudReflector dalamudReflector, IChatGui chatGui, IPluginLog pluginLog)
{ {
_dalamudReflector = dalamudReflector; _dalamudReflector = dalamudReflector;
_chatGui = chatGui;
_pluginLog = pluginLog;
} }
[SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")]
@ -24,41 +28,58 @@ internal sealed class SubmarineTrackerIpc
{ {
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); .Select(x => new SubmarineInfo(x.Fc!, x.Subs))
.GroupBy(x => x.Fc)
.ToDictionary(x => x.Key, x =>
{
if (x.Count() != 1)
{
_chatGui.PrintError($"[Influx] Unable to collect data, FC '{x.Key.Name}' is included in statistics through multiple characters/owners.");
var characterNames = characters.Where(y => y.FreeCompanyId == x.Key.CharacterId).Select(y => y.Name).ToList();
throw new InvalidOperationException($"Unable to collect FC data for FC '{x.Key}'{Environment.NewLine}Multiple characters include the same FC ({string.Join(", ", characterNames)}), only one of them should have 'Include Free Company Statistics' set");
}
return x.Single().Subs;
});
} }
else else
return new Dictionary<Character, List<SubmarineStats>>(); return new Dictionary<Character, List<SubmarineStats>>();
} }
private sealed record SubmarineInfo(Character? Fc, List<SubmarineStats> Subs) private sealed record SubmarineInfo(Character Fc, List<SubmarineStats> Subs)
{ {
public SubmarineInfo(Character? fc, List<Submarine> subs) public SubmarineInfo(Character fc, IList<Submarine> subs)
: this(fc, subs.Select(x => Convert(fc, subs.IndexOf(x), x)).ToList()) : this(fc, subs.Select(x => Convert(fc, subs.IndexOf(x), x)).ToList())
{ {
} }
private static SubmarineStats Convert(Character? fc, int index, Submarine y) private static SubmarineStats Convert(Character fc, int index, Submarine y)
{ {
return new SubmarineStats return new SubmarineStats
{ {
Id = index, Id = index,
Name = y.Name, Name = y.Name,
WorldId = fc?.WorldId ?? 0, WorldId = fc.WorldId,
Level = y.Level, Level = y.Level,
PredictedLevel = y.PredictedLevel, PredictedLevel = y.PredictedLevel,
Hull = y.Build.HullIdentifier, Hull = y.Build.HullIdentifier,

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

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