Compare commits

...

5 Commits

Author SHA1 Message Date
Liza f80b694d60
Fix FC Credits 2024-08-01 17:53:49 +02:00
Liza 859cd4500e
Make plugin compatible with AllaganTools 1.7.0.11+ 2024-07-14 16:11:27 +02:00
Liza 0a313e8fa3
API 10 2024-07-03 10:24:22 +02:00
Liza 090d1f8dca
Fix submarine tracker integration 2024-06-18 21:58:29 +02:00
Liza f2b51b38c2
Hopefully fix all AllaganTools code 2024-06-06 22:01:06 +02:00
24 changed files with 211 additions and 207 deletions

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

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

View File

@ -1,6 +1,7 @@
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;
@ -21,9 +22,9 @@ internal sealed class AllaganToolsIpc : IDisposable
private ICharacterMonitor _characters; private ICharacterMonitor _characters;
private IInventoryMonitor _inventories; private IInventoryMonitor _inventories;
private IFilterService _filters; private IListService _lists;
public AllaganToolsIpc(DalamudPluginInterface pluginInterface, IChatGui chatGui, DalamudReflector dalamudReflector, public AllaganToolsIpc(IDalamudPluginInterface pluginInterface, IChatGui chatGui, DalamudReflector dalamudReflector,
IFramework framework, IPluginLog pluginLog) IFramework framework, IPluginLog pluginLog)
{ {
_chatGui = chatGui; _chatGui = chatGui;
@ -37,7 +38,7 @@ internal sealed class AllaganToolsIpc : IDisposable
_characters = new UnavailableCharacterMonitor(_pluginLog); _characters = new UnavailableCharacterMonitor(_pluginLog);
_inventories = new UnavailableInventoryMonitor(_pluginLog); _inventories = new UnavailableInventoryMonitor(_pluginLog);
_filters = new UnavailableFilterService(_pluginLog); _lists = new UnavailableListService(_pluginLog);
_initialized.Subscribe(ConfigureIpc); _initialized.Subscribe(ConfigureIpc);
@ -64,12 +65,25 @@ 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 pluginService = it.GetType().Assembly.GetType("InventoryTools.PluginService")!; var hostedPlugin = it.GetType().BaseType!;
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])!;
_characters = new CharacterMonitor(pluginService.GetProperty("CharacterMonitor")!.GetValue(null)!); var ccl = it.GetType()
.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(
pluginService.GetProperty("InventoryMonitor")!.GetValue(null)!); GetService(ccl.GetType("CriticalCommonLib.Services.IInventoryMonitor")!));
_filters = new FilterService(pluginService.GetProperty("FilterService")!.GetValue(null)!); _lists = new ListService(
GetService(it.GetType().Assembly.GetType("InventoryTools.Services.Interfaces.IListService")!),
GetService(it.GetType().Assembly.GetType("InventoryTools.Lists.ListFilterService")!));
} }
else else
{ {
@ -97,11 +111,11 @@ internal sealed class AllaganToolsIpc : IDisposable
} }
} }
public Filter? GetFilter(string keyOrName) public FilterResult? GetFilter(string keyOrName)
{ {
try try
{ {
return _filters.GetFilterByKeyOrName(keyOrName); return _lists.GetFilterByKeyOrName(keyOrName);
} }
catch (IpcError e) catch (IpcError e)
{ {
@ -112,7 +126,7 @@ internal sealed class AllaganToolsIpc : IDisposable
public Dictionary<Character, Currencies> CountCurrencies() public Dictionary<Character, Currencies> CountCurrencies()
{ {
_pluginLog.Debug($"{_characters.GetType()}, {_inventories.GetType()}"); _pluginLog.Verbose($"Updating characters with {_characters.GetType()} and {_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))
@ -140,7 +154,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);
_filters = new UnavailableFilterService(_pluginLog); _lists = new UnavailableListService(_pluginLog);
} }
private sealed class InventoryWrapper(IEnumerable<InventoryItem> items) private sealed class InventoryWrapper(IEnumerable<InventoryItem> items)

View File

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

View File

@ -7,23 +7,22 @@ using System.Threading.Tasks;
namespace Influx.AllaganTools; namespace Influx.AllaganTools;
internal sealed class Filter internal sealed class FilterResult
{ {
private readonly object _delegate; private readonly object _delegate;
private readonly MethodInfo _generateFilteredList; private readonly PropertyInfo _sortedItems;
public Filter(object @delegate) public FilterResult(object @delegate)
{ {
ArgumentNullException.ThrowIfNull(@delegate); ArgumentNullException.ThrowIfNull(@delegate);
_delegate = @delegate; _delegate = @delegate;
_generateFilteredList = _delegate.GetType().GetMethod("GenerateFilteredList")!; _sortedItems =
_delegate.GetType().GetProperty("SortedItems") ?? throw new MissingMemberException();
} }
public IReadOnlyList<SortingResult> GenerateFilteredList() public IReadOnlyList<SortingResult> GenerateFilteredList()
{ {
Task task = (Task)_generateFilteredList.Invoke(_delegate, new object?[] { null })!; return ((IEnumerable)_sortedItems.GetValue(_delegate)!)
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

@ -1,23 +0,0 @@
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

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

View File

@ -0,0 +1,6 @@
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")!; _getAllInventories = _delegate.GetType().GetMethod("GetAllInventories") ?? throw new MissingMethodException();
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 FFXIVClientStructs.FFXIV.Client.Game; using Dalamud.Logging;
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().GetField("ItemId")!.GetValue(@delegate)!; ItemId = (uint)@delegate.GetType().GetProperty("ItemId")!.GetValue(@delegate)!;
Quantity = (uint)@delegate.GetType().GetField("Quantity")!.GetValue(@delegate)!; Quantity = (uint)@delegate.GetType().GetField("Quantity")!.GetValue(@delegate)!;
} }

View File

@ -0,0 +1,28 @@
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().GetField("ItemId")!.GetValue(inventoryItem)!; ItemId = (uint)inventoryItem.GetType().GetProperty("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.HQ); public bool IsHq => Flags.HasFlag(ItemFlags.HighQuality);
public override string ToString() public override string ToString()
{ {

View File

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

View File

@ -1,58 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Dalamud.NET.Sdk/10.0.0">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework> <Version>1.2</Version>
<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>
<PropertyGroup> <Import Project="..\LLib\LLib.targets"/>
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath> <Import Project="..\LLib\RenameZip.targets"/>
</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="8.0.3" /> <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0-preview.1.24081.5" />
</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>
@ -60,8 +17,4 @@
<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,6 +216,10 @@ 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 DalamudPluginInterface _pluginInterface; private readonly IDalamudPluginInterface _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(DalamudPluginInterface pluginInterface, IClientState clientState, IPluginLog pluginLog, public InfluxPlugin(IDalamudPluginInterface 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, chatGui, pluginLog); _submarineTrackerIpc = new SubmarineTrackerIpc(dalamudReflector);
_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 DalamudPluginInterface _pluginInterface; private readonly IDalamudPluginInterface _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,
DalamudPluginInterface pluginInterface, IDalamudPluginInterface 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 > 50) if (atkArrays.NumberArrayCount > 51)
{ {
var fcArrayData = atkArrays.GetNumberArrayData(50); var fcArrayData = atkArrays.GetNumberArrayData(51);
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 DalamudPluginInterface _pluginInterface; private readonly IDalamudPluginInterface _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(
DalamudPluginInterface pluginInterface, IDalamudPluginInterface pluginInterface,
IClientState clientState, IClientState clientState,
IAddonLifecycle addonLifecycle, IAddonLifecycle addonLifecycle,
IPluginLog pluginLog, IPluginLog pluginLog,
@ -58,11 +58,9 @@ 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 <= 12)) foreach (var quest in dataManager.GetExcelSheet<Quest>()!.Where(x => x.JournalGenre.Row is >= 1 and <= 13))
{ {
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
{ {
@ -248,8 +246,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 < 30; ++i) for (int i = 0; i < 32; ++i)
levels.Add(playerState->ClassJobLevelArray[i]); levels.Add(playerState->ClassJobLevels[i]);
return levels; return levels;
} }

View File

@ -1,21 +0,0 @@
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,9 +8,11 @@ internal sealed class Submarine
{ {
ArgumentNullException.ThrowIfNull(@delegate); ArgumentNullException.ThrowIfNull(@delegate);
Type type = @delegate.GetType(); Type type = @delegate.GetType();
Name = (string)type.GetProperty("Name")!.GetValue(@delegate)!; FreeCompanyId = (ulong)type.GetField("FreeCompanyId")!.GetValue(@delegate)!;
Level = (ushort)type.GetProperty("Rank")!.GetValue(@delegate)!; Name = (string)type.GetField("Name")!.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
{ {
@ -28,8 +30,6 @@ 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,6 +37,7 @@ 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,14 +13,10 @@ 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, IChatGui chatGui, IPluginLog pluginLog) public SubmarineTrackerIpc(DalamudReflector dalamudReflector)
{ {
_dalamudReflector = dalamudReflector; _dalamudReflector = dalamudReflector;
_chatGui = chatGui;
_pluginLog = pluginLog;
} }
[SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")]
@ -28,58 +24,41 @@ 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 submarineData = it.GetType().Assembly.GetType("SubmarineTracker.Data.Submarines"); var databaseCache = it.GetType()
var knownSubmarineData = submarineData!.GetField("KnownSubmarines")!; .GetField("DatabaseCache", BindingFlags.Static | BindingFlags.Public)!
return ((IEnumerable)knownSubmarineData.GetValue(null)!).Cast<object>() .GetValue(null)!;
.Select(x => new var getSubmarines = databaseCache.GetType()
{ .GetMethod("GetSubmarines", [])!;
OwnerId = (ulong)x.GetType().GetProperty("Key")!.GetValue(x)!, var knownSubmarineData = ((IEnumerable)getSubmarines.Invoke(databaseCache, [])!).Cast<object>();
FcWrapper = x.GetType().GetProperty("Value")!.GetValue(x)! return knownSubmarineData
}) .Select(x => new Submarine(x))
.Select(x => new .GroupBy(x => x.FreeCompanyId)
{ .Select(x => new SubmarineInfo(
Owner = characters.FirstOrDefault(y => y.CharacterId == x.OwnerId), characters.SingleOrDefault(y =>
Subs = new FcSubmarines(x.FcWrapper).Submarines, y.CharacterType == CharacterType.FreeCompanyChest && y.CharacterId == x.Key),
}) 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)
.Select(x => new SubmarineInfo(x.Fc!, x.Subs)) .ToDictionary(x => x.Fc!, x => 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, IList<Submarine> subs) public SubmarineInfo(Character? fc, List<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, WorldId = fc?.WorldId ?? 0,
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 DalamudPluginInterface _pluginInterface; private readonly IDalamudPluginInterface _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 = Array.Empty<string>(); private string[] _filterNames = [];
private int _filterIndexToAdd; private int _filterIndexToAdd;
public ConfigurationWindow(DalamudPluginInterface pluginInterface, IClientState clientState, public ConfigurationWindow(IDalamudPluginInterface pluginInterface, IClientState clientState,
Configuration configuration, AllaganToolsIpc allaganToolsIpc) Configuration configuration, AllaganToolsIpc allaganToolsIpc)
: base("Configuration###InfluxConfiguration") : base("Configuration###InfluxConfiguration")
{ {

View File

@ -4,9 +4,21 @@
"net8.0-windows7.0": { "net8.0-windows7.0": {
"DalamudPackager": { "DalamudPackager": {
"type": "Direct", "type": "Direct",
"requested": "[2.1.12, )", "requested": "[2.1.13, )",
"resolved": "2.1.12", "resolved": "2.1.13",
"contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg==" "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ=="
},
"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",
@ -25,9 +37,19 @@
}, },
"Microsoft.Extensions.ObjectPool": { "Microsoft.Extensions.ObjectPool": {
"type": "Direct", "type": "Direct",
"requested": "[8.0.3, )", "requested": "[9.0.0-preview.1.24081.5, )",
"resolved": "8.0.3", "resolved": "9.0.0-preview.1.24081.5",
"contentHash": "sk/TGiccSeXUtVeBfFlWJnzp6xLlAxIW+bCHs7uVPLFPQk8vICNmu9Gc3JsKOn6fQuRkrPetQ8EHv4dCiMqhxg==" "contentHash": "aAR7YW+pUUdvHk3vj7GtAi71dWGDIuY9270lsmQ6lKw23zzY+r8pLP3cGNbJdlnA9VWl+S+gnIVkBCqj2ROlEg=="
},
"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",
@ -54,6 +76,11 @@
"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",
@ -72,6 +99,47 @@
"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",
@ -195,14 +263,17 @@
"autoretainerapi": { "autoretainerapi": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"ECommons": "[2.1.0.7, )" "ECommons": "[2.2.0.2, )"
} }
}, },
"ecommons": { "ecommons": {
"type": "Project" "type": "Project"
}, },
"llib": { "llib": {
"type": "Project" "type": "Project",
"dependencies": {
"DalamudPackager": "[2.1.13, )"
}
} }
} }
} }

2
LLib

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