Calculate optimal gearset choice on a separate thread

master v1.1
Liza 2024-07-08 23:11:21 +02:00
parent ae706b0461
commit 1845ebf701
Signed by: liza
GPG Key ID: 7199F8D727D55F67
4 changed files with 120 additions and 46 deletions

View File

@ -1,6 +1,6 @@
<Project Sdk="Dalamud.NET.Sdk/9.0.2">
<PropertyGroup>
<Version>1.0</Version>
<Version>1.1</Version>
<OutputPath>dist</OutputPath>
</PropertyGroup>

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
using Dalamud.Game.Command;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
@ -121,6 +122,7 @@ public sealed class GearsetterPlugin : IDalamudPlugin
private unsafe void ShowUpgrades(byte? level = null)
{
DateTime start = DateTime.Now;
var inventoryItems = GetAllInventoryItems();
var gearsetModule = RaptureGearsetModule.Instance();
@ -131,7 +133,7 @@ public sealed class GearsetterPlugin : IDalamudPlugin
if (onlyCurrentJob)
_chatGui.Print("Checking only gearsets for your current class/job...");
bool anyUpgrade = false;
List<GearsetData> gearsets = new List<GearsetData>();
for (int i = 0; i < 100; ++i)
{
var gearset = gearsetModule->GetGearset(i);
@ -140,44 +142,65 @@ public sealed class GearsetterPlugin : IDalamudPlugin
if (onlyCurrentJob && gearset->ClassJob != _clientState.LocalPlayer!.ClassJob.Id)
continue;
anyUpgrade |= HandleGearset(gearset, inventoryItems, level);
var gearsetData = PrepareGearset(gearset);
if (gearsetData != null)
gearsets.Add(gearsetData);
}
}
if (!anyUpgrade)
_chatGui.Print("All your gearsets are OK.");
_pluginLog.Information($"Preparing gearsets took {DateTime.Now - start}");
Task.Run(() =>
{
start = DateTime.Now;
bool anyUpgrade = false;
foreach (GearsetData gearset in gearsets)
anyUpgrade |= HandleGearset(gearset, inventoryItems, level);
if (!anyUpgrade)
_chatGui.Print("All your gearsets are OK.");
_pluginLog.Information($"Evaluating gearsets took {DateTime.Now - start}");
});
}
private unsafe bool HandleGearset(RaptureGearsetModule.GearsetEntry* gearset,
Dictionary<(uint ItemId, bool Hq), List<MateriaStats>> inventoryItems, byte? level)
private unsafe GearsetData? PrepareGearset(RaptureGearsetModule.GearsetEntry* gearset)
{
string name = GetGearsetName(gearset);
if (name.Contains('_', StringComparison.Ordinal) ||
name.Contains("Eureka", StringComparison.OrdinalIgnoreCase) ||
name.Contains("Bozja", StringComparison.OrdinalIgnoreCase))
return false;
return null;
List<SeString> Handle(string label, RaptureGearsetModule.GearsetItemIndex[] spanIds, EEquipSlotCategory category)
return new GearsetData(_dataManager, gearset, name);
}
private bool HandleGearset(GearsetData gearset,
Dictionary<(uint ItemId, bool Hq), List<MateriaStats>> inventoryItems, byte? level)
{
List<SeString> Handle(string label, EquipmentItem?[] gearsetItems,
EEquipSlotCategory category)
{
return HandleGearsetItem(label, gearset, spanIds.Select(x => gearset->GetItem(x)).ToArray(),
inventoryItems, category, level);
return HandleGearsetItem(label, gearset, gearsetItems, inventoryItems, category, level);
}
List<List<SeString>> upgrades = new()
{
Handle("Main Hand", [RaptureGearsetModule.GearsetItemIndex.MainHand], EEquipSlotCategory.None),
Handle("Main Hand", [gearset.MainHand], EEquipSlotCategory.None),
HandleOffHand(gearset, inventoryItems, level),
Handle("Head", [RaptureGearsetModule.GearsetItemIndex.Head], EEquipSlotCategory.Head),
Handle("Body", [RaptureGearsetModule.GearsetItemIndex.Body], EEquipSlotCategory.Body),
Handle("Hands", [RaptureGearsetModule.GearsetItemIndex.Hands], EEquipSlotCategory.Hands),
Handle("Legs", [RaptureGearsetModule.GearsetItemIndex.Legs], EEquipSlotCategory.Legs),
Handle("Feet", [RaptureGearsetModule.GearsetItemIndex.Feet], EEquipSlotCategory.Feet),
Handle("Head", [gearset.Head], EEquipSlotCategory.Head),
Handle("Body", [gearset.Body], EEquipSlotCategory.Body),
Handle("Hands", [gearset.Hands], EEquipSlotCategory.Hands),
Handle("Legs", [gearset.Legs], EEquipSlotCategory.Legs),
Handle("Feet", [gearset.Feet], EEquipSlotCategory.Feet),
Handle("Ears", [RaptureGearsetModule.GearsetItemIndex.Ears], EEquipSlotCategory.Ears),
Handle("Neck", [RaptureGearsetModule.GearsetItemIndex.Neck], EEquipSlotCategory.Neck),
Handle("Wrists", [RaptureGearsetModule.GearsetItemIndex.Wrists], EEquipSlotCategory.Wrists),
Handle("Rings", [RaptureGearsetModule.GearsetItemIndex.RingLeft, RaptureGearsetModule.GearsetItemIndex.RingRight], EEquipSlotCategory.Rings),
Handle("Ears", [gearset.Ears], EEquipSlotCategory.Ears),
Handle("Neck", [gearset.Neck], EEquipSlotCategory.Neck),
Handle("Wrists", [gearset.Wrists], EEquipSlotCategory.Wrists),
Handle("Rings",
[gearset.RingLeft, gearset.RingRight],
EEquipSlotCategory.Rings),
};
List<SeString> flatUpgrades = upgrades.SelectMany(x => x).ToList();
@ -188,9 +211,9 @@ public sealed class GearsetterPlugin : IDalamudPlugin
new SeStringBuilder()
.Append("Gearset ")
.AddUiForeground(1)
.Add(_linkPayloads[gearset->Id])
.Append($"#{gearset->Id + 1}: ")
.Append(name)
.Add(_linkPayloads[gearset.Id])
.Append($"#{gearset.Id + 1}: ")
.Append(gearset.Name)
.Add(RawPayload.LinkTerminator)
.AddUiForegroundOff()
.AddText(level != null ? $" at {level}" : "")
@ -209,20 +232,18 @@ public sealed class GearsetterPlugin : IDalamudPlugin
private unsafe string GetGearsetName(RaptureGearsetModule.GearsetEntry* gearset)
=> gearset->NameString.Split((char)0)[0];
private unsafe List<SeString> HandleGearsetItem(string label, RaptureGearsetModule.GearsetEntry* gearset,
RaptureGearsetModule.GearsetItem[] gearsetItem,
private List<SeString> HandleGearsetItem(string label, GearsetData gearset,
EquipmentItem?[] gearsetItems,
Dictionary<(uint ItemId, bool Hq), List<MateriaStats>> inventoryItems,
EEquipSlotCategory equipSlotCategory, byte? level)
{
EClassJob classJob = (EClassJob)gearset->ClassJob;
EClassJob classJob = gearset.ClassJob;
var itemLists = _gameDataHolder.GetItemLists(classJob);
if (gearsetItem.Any(x => x.ItemId > 0))
if (equipSlotCategory == EEquipSlotCategory.None && gearsetItems.Any(x => x != null))
{
var firstEquippedItem = gearsetItem.First(x => x.ItemId > 0);
equipSlotCategory = (EEquipSlotCategory)(_dataManager.GetExcelSheet<Item>()!
.GetRow(firstEquippedItem.ItemId % 1_000_000)
?.EquipSlotCategory?.Row ?? 0);
var firstEquippedItem = gearsetItems.First(x => x != null);
equipSlotCategory = firstEquippedItem!.EquipSlotCategory;
}
if (equipSlotCategory == EEquipSlotCategory.None)
@ -231,14 +252,10 @@ public sealed class GearsetterPlugin : IDalamudPlugin
return new List<SeString>();
}
BaseItem?[] currentItems = gearsetItem.Select(x => new
{
ItemId = x.ItemId % 1_000_000,
Hq = x.ItemId > 1_000_000
})
BaseItem?[] currentItems = gearsetItems
.Select(x =>
{
if (x.ItemId == 0)
if (x == null)
return null;
return itemLists
@ -261,7 +278,7 @@ public sealed class GearsetterPlugin : IDalamudPlugin
var bestItems = availableList.Items
.Where(x => x.Level <= level)
.Where(x => x is Model.InventoryItem)
.Take(gearsetItem.Length)
.Take(gearsetItems.Length)
.ToList();
//_pluginLog.Debug(
// $"{equipSlotCategory}: {string.Join(" ", currentItems.Select(x => $"{x?.ItemId}|{x?.Hq}"))}");
@ -284,20 +301,20 @@ public sealed class GearsetterPlugin : IDalamudPlugin
}
private unsafe List<SeString> HandleOffHand(RaptureGearsetModule.GearsetEntry* gearset,
private unsafe List<SeString> HandleOffHand(GearsetData gearset,
Dictionary<(uint ItemId, bool Hq), List<MateriaStats>> inventoryItems, byte? level)
{
var mainHand = gearset->GetItem(RaptureGearsetModule.GearsetItemIndex.MainHand);
if (mainHand.ItemId == 0)
var mainHand = gearset.MainHand;
if (mainHand == null)
return new List<SeString>();
// if it's a twohanded weapon, ignore it
EEquipSlotCategory equipSlotCategory =
(EEquipSlotCategory)(_dataManager.GetExcelSheet<Item>()!.GetRow(mainHand.ItemId % 1_000_000)?.RowId ?? 0);
EEquipSlotCategory equipSlotCategory = mainHand.EquipSlotCategory;
if (equipSlotCategory != EEquipSlotCategory.OneHandedMainHand)
return new List<SeString>();
return HandleGearsetItem("Off Hand", gearset, [gearset->GetItem(RaptureGearsetModule.GearsetItemIndex.OffHand)], inventoryItems,
return HandleGearsetItem("Off Hand", gearset, [gearset.OffHand],
inventoryItems,
EEquipSlotCategory.Shield, level);
}

View File

@ -0,0 +1,56 @@
using System.Collections.Generic;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using Gearsetter.GameData;
using Lumina.Excel.GeneratedSheets;
namespace Gearsetter.Model;
internal sealed class GearsetData
{
public unsafe GearsetData(IDataManager dataManager, RaptureGearsetModule.GearsetEntry* gearset, string name)
{
Id = gearset->Id;
ClassJob = (EClassJob)gearset->ClassJob;
Name = name;
MainHand = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.MainHand);
OffHand = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.OffHand);
Head = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.Head);
Body = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.Body);
Hands = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.Hands);
Legs = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.Legs);
Feet = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.Feet);
Ears = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.Ears);
Neck = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.Neck);
Wrists = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.Wrists);
RingLeft = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.RingLeft);
RingRight = GetItem(dataManager, gearset, RaptureGearsetModule.GearsetItemIndex.RingRight);
}
private static unsafe EquipmentItem? GetItem(IDataManager dataManager, RaptureGearsetModule.GearsetEntry* gearset,
RaptureGearsetModule.GearsetItemIndex index)
{
var gearsetItem = gearset->GetItem(index);
if (gearsetItem.ItemId == 0)
return null;
var item = dataManager.GetExcelSheet<Item>()!.GetRow(gearsetItem.ItemId % 1_000_000)!;
return new EquipmentItem(item, gearsetItem.ItemId > 1_000_000);
}
public byte Id { get; }
public EClassJob ClassJob { get; }
public string Name { get; }
public EquipmentItem? MainHand { get; }
public EquipmentItem? OffHand { get; }
public EquipmentItem? Head { get; }
public EquipmentItem? Body { get; }
public EquipmentItem? Hands { get; }
public EquipmentItem? Legs { get; }
public EquipmentItem? Feet { get; }
public EquipmentItem? Ears { get; set; }
public EquipmentItem? Neck { get; set; }
public EquipmentItem? Wrists { get; }
public EquipmentItem? RingLeft { get; }
public EquipmentItem? RingRight { get; }
}

View File

@ -141,7 +141,8 @@ internal sealed class EquipmentBrowserWindow : LWindow
ImGui.TableHeadersRow();
ImGui.PushStyleColor(ImGuiCol.HeaderHovered, hoverColor);
foreach (var item in itemList.Items.DistinctBy(x => new { x.ItemId, x.Hq, Materia = x.MateriaStats?.GetHashCode() }))
foreach (var item in itemList.Items.DistinctBy(x => new
{ x.ItemId, x.Hq, Materia = x.MateriaStats?.GetHashCode() }))
{
if (item is not InventoryItem)
{