Change to ExdSheets 2

This commit is contained in:
Asriel Camora
2024-08-06 11:53:03 -07:00
parent ff7d7693ad
commit fa45ac072e
16 changed files with 181 additions and 185 deletions
+1 -1
View File
@@ -20,7 +20,7 @@
<PackageReference Include="BenchmarkDotNet" Version="0.13.10" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.dotTrace" Version="0.13.10" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.10" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.162">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
+4 -3
View File
@@ -39,10 +39,11 @@
<ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.13" />
<PackageReference Include="ExdSheets" Version="1.2.2" />
<PackageReference Include="Lumina" Version="3.15.2" ExcludeAssets="all" />
<PackageReference Include="ExdSheets" Version="2.1.0" />
<PackageReference Include="Lumina" Version="4.1.1" ExcludeAssets="all" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0-preview.1.24081.5" ExcludeAssets="all" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.162">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
+4 -4
View File
@@ -290,7 +290,7 @@ internal static class ImGuiUtils
}
}
private sealed class SearchableComboData<T> where T : class
private sealed class SearchableComboData<T> where T : IEquatable<T>
{
public readonly ImmutableArray<T> items;
public List<T> filteredItems;
@@ -314,7 +314,7 @@ internal static class ImGuiUtils
public void SetItem(T selectedItem)
{
if (this.selectedItem != selectedItem)
if (!this.selectedItem.Equals(selectedItem))
{
input = GetString(selectedItem);
this.selectedItem = selectedItem;
@@ -364,14 +364,14 @@ internal static class ImGuiUtils
}
private static readonly Dictionary<uint, object> ComboData = [];
private static SearchableComboData<T> GetComboData<T>(uint comboKey, IEnumerable<T> items, T selectedItem, Func<T, string> getString) where T : class =>
private static SearchableComboData<T> GetComboData<T>(uint comboKey, IEnumerable<T> items, T selectedItem, Func<T, string> getString) where T : IEquatable<T> =>
(SearchableComboData<T>)(
ComboData.TryGetValue(comboKey, out var data)
? data
: ComboData[comboKey] = new SearchableComboData<T>(items, selectedItem, getString));
// https://github.com/ocornut/imgui/issues/718#issuecomment-1563162222
public static bool SearchableCombo<T>(string id, ref T selectedItem, IEnumerable<T> items, ImFontPtr selectableFont, float width, Func<T, string> getString, Func<T, string> getId, Action<T> draw) where T : class
public static bool SearchableCombo<T>(string id, ref T selectedItem, IEnumerable<T> items, ImFontPtr selectableFont, float width, Func<T, string> getString, Func<T, string> getId, Action<T> draw) where T : IEquatable<T>
{
var comboKey = ImGui.GetID(id);
var data = GetComboData(comboKey, items, selectedItem, getString);
+19 -29
View File
@@ -1,37 +1,27 @@
using Dalamud.Game;
using Dalamud.Utility;
using ExdSheets;
using Lumina.Excel;
using System.Collections.Concurrent;
using ExdSheets.Sheets;
using Lumina.Data;
namespace Craftimizer.Plugin;
public static class LuminaSheets
{
public static readonly ExcelSheet<Recipe> RecipeSheet = Service.DataManager.GetExcelSheet<Recipe>()!;
public static readonly ExcelSheet<Action> ActionSheet = Service.DataManager.GetExcelSheet<Action>()!;
public static readonly ExcelSheet<CraftAction> CraftActionSheet = Service.DataManager.GetExcelSheet<CraftAction>()!;
public static readonly ExcelSheet<Status> StatusSheet = Service.DataManager.GetExcelSheet<Status>()!;
public static readonly ExcelSheet<Addon> AddonSheet = Service.DataManager.GetExcelSheet<Addon>()!;
public static readonly ExcelSheet<ClassJob> ClassJobSheet = Service.DataManager.GetExcelSheet<ClassJob>()!;
public static readonly ExcelSheet<Item> ItemSheet = Service.DataManager.GetExcelSheet<Item>()!;
public static readonly ExcelSheet<Item> ItemSheetEnglish = Service.DataManager.GetExcelSheet<Item>(ClientLanguage.English)!;
public static readonly ExcelSheet<ENpcResident> ENpcResidentSheet = Service.DataManager.GetExcelSheet<ENpcResident>()!;
public static readonly ExcelSheet<Level> LevelSheet = Service.DataManager.GetExcelSheet<Level>()!;
public static readonly ExcelSheet<Quest> QuestSheet = Service.DataManager.GetExcelSheet<Quest>()!;
public static readonly ExcelSheet<Materia> MateriaSheet = Service.DataManager.GetExcelSheet<Materia>()!;
public static readonly ExcelSheet<BaseParam> BaseParamSheet = Service.DataManager.GetExcelSheet<BaseParam>()!;
public static readonly ExcelSheet<ItemFood> ItemFoodSheet = Service.DataManager.GetExcelSheet<ItemFood>()!;
public static readonly ExcelSheet<SatisfactionSupply> SatisfactionSupplySheet = Service.DataManager.GetExcelSheet<SatisfactionSupply>()!;
private static readonly Module Module = new(Service.DataManager.GameData, Service.DataManager.Language.ToLumina());
private static ConcurrentDictionary<(ExcelSheetImpl, uint), uint> SubRowCountCache { get; } = new();
public static uint? GetSubRowCount<T>(this ExcelSheet<T> sheet, uint row) where T : ExcelRow
{
if (SubRowCountCache.TryGetValue((sheet, row), out var count))
return count;
var parser = sheet.GetRowParser(row);
if (parser == null)
return null;
SubRowCountCache.TryAdd((sheet, row), parser.RowCount);
return parser.RowCount;
}
public static readonly Sheet<Recipe> RecipeSheet = Module.GetSheet<Recipe>();
public static readonly Sheet<Action> ActionSheet = Module.GetSheet<Action>();
public static readonly Sheet<CraftAction> CraftActionSheet = Module.GetSheet<CraftAction>();
public static readonly Sheet<Status> StatusSheet = Module.GetSheet<Status>();
public static readonly Sheet<Addon> AddonSheet = Module.GetSheet<Addon>();
public static readonly Sheet<ClassJob> ClassJobSheet = Module.GetSheet<ClassJob>();
public static readonly Sheet<Item> ItemSheet = Module.GetSheet<Item>();
public static readonly Sheet<Item> ItemSheetEnglish = Module.GetSheet<Item>(Language.English)!;
public static readonly Sheet<ENpcResident> ENpcResidentSheet = Module.GetSheet<ENpcResident>();
public static readonly Sheet<Level> LevelSheet = Module.GetSheet<Level>();
public static readonly Sheet<Quest> QuestSheet = Module.GetSheet<Quest>();
public static readonly Sheet<Materia> MateriaSheet = Module.GetSheet<Materia>();
public static readonly Sheet<BaseParam> BaseParamSheet = Module.GetSheet<BaseParam>();
public static readonly Sheet<ItemFood> ItemFoodSheet = Module.GetSheet<ItemFood>();
public static readonly Sheet<SatisfactionSupply> SatisfactionSupplySheet = Module.GetSheet<SatisfactionSupply>();
}
+1 -1
View File
@@ -62,7 +62,7 @@ public sealed class Plugin : IDalamudPlugin
SynthHelperWindow = new();
ListWindow = new();
// Trigger static constructors so a huge hitch doesn't occur on first RecipeNote frame.
// Trigger static constructors so a hitch doesn't occur on first RecipeNote frame.
FoodStatus.Initialize();
ActionUtils.Initialize();
+45 -51
View File
@@ -1,21 +1,19 @@
using Craftimizer.Simulator;
using Craftimizer.Simulator.Actions;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
using ExdSheets;
using System;
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Text;
using Action = ExdSheets.Action;
using Action = ExdSheets.Sheets.Action;
using ActionType = Craftimizer.Simulator.Actions.ActionType;
using ClassJob = Craftimizer.Simulator.ClassJob;
using Condition = Craftimizer.Simulator.Condition;
using Status = ExdSheets.Status;
using Dalamud.Interface.Textures;
using Status = ExdSheets.Sheets.Status;
using Craftimizer.Utils;
using ExdSheets.Sheets;
using Lumina.Text.ReadOnly;
using Lumina.Text.Payloads;
namespace Craftimizer.Plugin;
@@ -31,33 +29,33 @@ internal static class ActionUtils
foreach (var actionType in actionTypes)
{
var actionId = actionType.Base().ActionId;
if (LuminaSheets.CraftActionSheet.GetRow(actionId) is CraftAction baseCraftAction)
if (LuminaSheets.CraftActionSheet.TryGetRow(actionId) is { } baseCraftAction)
{
foreach (var classJob in classJobs)
{
ActionRows[(int)actionType, (int)classJob] = (classJob switch
{
ClassJob.Carpenter => baseCraftAction.CRP.Value!,
ClassJob.Blacksmith => baseCraftAction.BSM.Value!,
ClassJob.Armorer => baseCraftAction.ARM.Value!,
ClassJob.Goldsmith => baseCraftAction.GSM.Value!,
ClassJob.Leatherworker => baseCraftAction.LTW.Value!,
ClassJob.Weaver => baseCraftAction.WVR.Value!,
ClassJob.Alchemist => baseCraftAction.ALC.Value!,
ClassJob.Culinarian => baseCraftAction.CUL.Value!,
ClassJob.Carpenter => baseCraftAction.CRP.Value,
ClassJob.Blacksmith => baseCraftAction.BSM.Value,
ClassJob.Armorer => baseCraftAction.ARM.Value,
ClassJob.Goldsmith => baseCraftAction.GSM.Value,
ClassJob.Leatherworker => baseCraftAction.LTW.Value,
ClassJob.Weaver => baseCraftAction.WVR.Value,
ClassJob.Alchemist => baseCraftAction.ALC.Value,
ClassJob.Culinarian => baseCraftAction.CUL.Value,
_ => baseCraftAction
}, null);
}
}
if (LuminaSheets.ActionSheet.GetRow(actionId) is Action baseAction)
if (LuminaSheets.ActionSheet.TryGetRow(actionId) is { } baseAction)
{
var possibleActions = LuminaSheets.ActionSheet.Where(r =>
r.Icon == baseAction.Icon &&
r.ActionCategory.Row == baseAction.ActionCategory.Row &&
r.Name.RawString.Equals(baseAction.Name.RawString, StringComparison.Ordinal));
r.ActionCategory.RowId == baseAction.ActionCategory.RowId &&
r.Name.Equals(baseAction.Name));
foreach (var classJob in classJobs)
ActionRows[(int)actionType, (int)classJob] = (null, possibleActions.First(r => r.ClassJobCategory.Value?.IsClassJob(classJob) ?? false));
ActionRows[(int)actionType, (int)classJob] = (null, possibleActions.First(r => r.ClassJobCategory.ValueNullable?.IsClassJob(classJob) ?? false));
}
}
}
@@ -70,32 +68,20 @@ internal static class ActionUtils
public static uint GetId(this ActionType me, ClassJob classJob)
{
var (craftAction, action) = GetActionRow(me, classJob);
if (craftAction != null)
return craftAction.RowId;
if (action != null)
return action.RowId;
return 0;
return craftAction?.RowId ?? action?.RowId ?? 0;
}
public static string GetName(this ActionType me, ClassJob classJob)
{
var (craftAction, action) = GetActionRow(me, classJob);
if (craftAction != null)
return craftAction.Name.ToDalamudString().TextValue;
if (action != null)
return action.Name.ToDalamudString().TextValue;
return "Unknown";
return (craftAction?.Name ?? action?.Name)?.AsSpan().ExtractText() ?? "Unknown";
}
public static ITextureIcon GetIcon(this ActionType me, ClassJob classJob)
{
var (craftAction, action) = GetActionRow(me, classJob);
if (craftAction != null)
return Service.IconManager.GetIconCached(craftAction.Icon);
if (action != null)
return Service.IconManager.GetIconCached(action.Icon);
// Old "Steady Hand" action icon
return Service.IconManager.GetIconCached(1953);
// 1953 = Old "Steady Hand" action icon
return Service.IconManager.GetIconCached(craftAction?.Icon ?? action?.Icon ?? 1953);
}
public static ActionType? GetActionTypeFromId(uint actionId, ClassJob classJob, bool isCraftAction)
@@ -155,18 +141,18 @@ internal static class ClassJobUtils
PlayerState.Instance()->ClassJobLevels[me.GetExpArrayIdx()];
public static unsafe bool CanPlayerUseManipulation(this ClassJob me) =>
UIState.Instance()->IsUnlockLinkUnlockedOrQuestCompleted(ActionType.Manipulation.GetActionRow(me).Action!.UnlockLink.Row);
UIState.Instance()->IsUnlockLinkUnlockedOrQuestCompleted(ActionType.Manipulation.GetActionRow(me).Action!.Value.UnlockLink.RowId);
public static string GetName(this ClassJob me)
{
var job = LuminaSheets.ClassJobSheet.GetRow(me.GetClassJobIndex())!;
return job.Name.ToDalamudString().TextValue.ToLowerInvariant();
var job = LuminaSheets.ClassJobSheet.GetRow(me.GetClassJobIndex());
return job.Name.ExtractText().ToLowerInvariant();
}
public static string GetNameArticle(this ClassJob me)
{
var job = LuminaSheets.ClassJobSheet.GetRow(me.GetClassJobIndex())!;
if (job.SheetLanguage == Lumina.Data.Language.English)
var job = LuminaSheets.ClassJobSheet.GetRow(me.GetClassJobIndex());
if (LuminaSheets.ClassJobSheet.Language == Lumina.Data.Language.English)
{
if (me is ClassJob.Alchemist or ClassJob.Armorer)
return "an";
@@ -176,12 +162,12 @@ internal static class ClassJobUtils
public static string GetAbbreviation(this ClassJob me)
{
var job = LuminaSheets.ClassJobSheet.GetRow(me.GetClassJobIndex())!;
return job.Abbreviation.ToDalamudString().TextValue;
var job = LuminaSheets.ClassJobSheet.GetRow(me.GetClassJobIndex());
return job.Abbreviation.ExtractText();
}
public static Quest GetUnlockQuest(this ClassJob me) =>
LuminaSheets.QuestSheet.GetRow(65720 + (uint)me) ?? throw new ArgumentException($"Could not get unlock quest for {me}", nameof(me));
LuminaSheets.QuestSheet.GetRow(65720 + (uint)me);
public static ushort GetIconId(this ClassJob me) =>
(ushort)(62000 + me.GetClassJobIndex());
@@ -295,15 +281,23 @@ internal static class ConditionUtils
}
public static string Name(this Condition me) =>
LuminaSheets.AddonSheet.GetRow(me.AddonIds().Name)!.Text.ToDalamudString().TextValue;
LuminaSheets.AddonSheet.GetRow(me.AddonIds().Name).Text.ExtractText();
public static string Description(this Condition me, bool isRelic)
{
var text = LuminaSheets.AddonSheet.GetRow(me.AddonIds().Description)!.Text.ToDalamudString();
for (var i = 0; i < text.Payloads.Count; ++i)
if (text.Payloads[i] is RawPayload)
text.Payloads[i] = new TextPayload(isRelic ? "1.75" : "1.5");
return text.TextValue;
var text = LuminaSheets.AddonSheet.GetRow(me.AddonIds().Description).Text;
if (!text.Any(p => p is { Type: ReadOnlySePayloadType.Macro, MacroCode: MacroCode.Float }))
return text.ExtractText();
ReadOnlySeString finalText = new();
foreach (var payload in text)
{
if (payload is { Type: ReadOnlySePayloadType.Macro, MacroCode: MacroCode.Float })
finalText += new ReadOnlySePayload(ReadOnlySePayloadType.Text, default, Encoding.UTF8.GetBytes(isRelic ? "1.75" : "1.5"));
else
finalText += payload;
}
return finalText.ExtractText();
}
}
@@ -349,7 +343,7 @@ internal static class EffectUtils
{
var status = me.Status();
var name = new StringBuilder();
name.Append(status.Name.ToDalamudString().TextValue);
name.Append(status.Name.ExtractText());
if (status.MaxStacks != 0)
name.Append($" {strength}");
if (!status.IsPermanent)
+10 -11
View File
@@ -1,5 +1,5 @@
using Craftimizer.Plugin;
using ExdSheets;
using ExdSheets.Sheets;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -25,28 +25,27 @@ public static class FoodStatus
var medicines = new Dictionary<uint, Food>();
foreach (var item in LuminaSheets.ItemSheet)
{
var isFood = item.ItemUICategory.Row == 46;
var isMedicine = item.ItemUICategory.Row == 44;
var isFood = item.ItemUICategory.RowId == 46;
var isMedicine = item.ItemUICategory.RowId == 44;
if (!isFood && !isMedicine)
continue;
if (item.ItemAction.Value == null)
if (item.ItemAction.ValueNullable is not { } itemAction)
continue;
if (!(item.ItemAction.Value.Type is 844 or 845 or 846))
if (itemAction.Type is not (844 or 845 or 846))
continue;
var itemFood = LuminaSheets.ItemFoodSheet.GetRow(item.ItemAction.Value.Data[1]);
if (itemFood == null)
if (LuminaSheets.ItemFoodSheet.TryGetRow(itemAction.Data[1]) is not { } itemFood)
continue;
FoodStat? craftsmanship = null, control = null, cp = null;
foreach (var stat in itemFood.Params)
{
if (stat.BaseParam.Row == 0)
if (stat.BaseParam.RowId == 0)
continue;
var foodStat = new FoodStat(stat.IsRelative, stat.Value, stat.Max, stat.ValueHQ, stat.MaxHQ);
switch (stat.BaseParam.Row)
switch (stat.BaseParam.RowId)
{
case Gearsets.ParamCraftsmanship: craftsmanship = foodStat; break;
case Gearsets.ParamControl: control = foodStat; break;
@@ -71,8 +70,8 @@ public static class FoodStatus
FoodItems = foods.ToFrozenDictionary();
MedicineItems = medicines.ToFrozenDictionary();
FoodOrder = FoodItems.OrderByDescending(a => a.Value.Item.LevelItem.Row).Select(a => a.Key).ToImmutableArray();
MedicineOrder = MedicineItems.OrderByDescending(a => a.Value.Item.LevelItem.Row).Select(a => a.Key).ToImmutableArray();
FoodOrder = FoodItems.OrderByDescending(a => a.Value.Item.LevelItem.RowId).Select(a => a.Key).ToImmutableArray();
MedicineOrder = MedicineItems.OrderByDescending(a => a.Value.Item.LevelItem.RowId).Select(a => a.Key).ToImmutableArray();
}
public static void Initialize() { }
+9 -9
View File
@@ -3,7 +3,7 @@ using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using ExdSheets;
using ExdSheets.Sheets;
using System;
using System.Linq;
using Craftimizer.Plugin;
@@ -62,10 +62,10 @@ public static unsafe class Gearsets
}
foreach (var statIncrease in item.BaseParam.Zip(item.BaseParamValue))
IncreaseStat(statIncrease.First.Row, statIncrease.Second);
IncreaseStat(statIncrease.First.RowId, statIncrease.Second);
if (gearsetItem.IsHq)
foreach (var statIncrease in item.BaseParamSpecial.Zip(item.BaseParamValueSpecial))
IncreaseStat(statIncrease.First.Row, statIncrease.Second);
IncreaseStat(statIncrease.First.RowId, statIncrease.Second);
foreach (var gearsetMateria in gearsetItem.Materia)
{
@@ -73,7 +73,7 @@ public static unsafe class Gearsets
continue;
var materia = LuminaSheets.MateriaSheet.GetRow(gearsetMateria.Type)!;
IncreaseStat(materia.BaseParam.Row, materia.Value[gearsetMateria.Grade]);
IncreaseStat(materia.BaseParam.RowId, materia.Value[gearsetMateria.Grade]);
}
cp = Math.Min(cp, CalculateParamCap(item, ParamCP));
@@ -125,17 +125,17 @@ public static unsafe class Gearsets
return false;
var luminaItem = LuminaSheets.ItemSheet.GetRow(item.ItemId)!;
// Soul Crystal ItemUICategory DoH Category
return luminaItem.ItemUICategory.Row == 62 && luminaItem.ClassJobUse.Value!.ClassJobCategory.Row == 33;
// Soul Crystal ItemUICategory DoH Category
return luminaItem.ItemUICategory.RowId == 62 && luminaItem.ClassJobUse.Value.ClassJobCategory.RowId == 33;
}
public static bool IsSplendorousTool(GearsetItem item) =>
LuminaSheets.ItemSheetEnglish.GetRow(item.ItemId)!.Description.ToDalamudString().TextValue.Contains("Increases to quality are 1.75 times higher than normal when material condition is Good.", StringComparison.Ordinal);
LuminaSheets.ItemSheetEnglish.GetRow(item.ItemId).Description.ExtractText().Contains("Increases to quality are 1.75 times higher than normal when material condition is Good.", StringComparison.Ordinal);
// https://github.com/ffxiv-teamcraft/ffxiv-teamcraft/blob/24d0db2d9676f264edf53651b21005305267c84c/apps/client/src/app/modules/gearsets/materia.service.ts#L265
private static int CalculateParamCap(Item item, uint paramId)
{
var ilvl = item.LevelItem.Value!;
var ilvl = item.LevelItem.Value;
var param = LuminaSheets.BaseParamSheet.GetRow(paramId)!;
var baseValue = paramId switch
@@ -146,7 +146,7 @@ public static unsafe class Gearsets
_ => 0
};
// https://github.com/ffxiv-teamcraft/ffxiv-teamcraft/blob/24d0db2d9676f264edf53651b21005305267c84c/apps/data-extraction/src/extractors/items.extractor.ts#L6
var slotMod = item.EquipSlotCategory.Row switch
var slotMod = item.EquipSlotCategory.RowId switch
{
1 => param.OneHandWeaponPercent, // column 4
2 => param.OffHandPercent, // column 5
+23 -29
View File
@@ -1,7 +1,6 @@
using Craftimizer.Plugin;
using Craftimizer.Simulator;
using ExdSheets;
using Lumina.Excel;
using ExdSheets.Sheets;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -18,7 +17,7 @@ public sealed record RecipeData
public ClassJob ClassJob { get; }
public RecipeInfo RecipeInfo { get; }
public bool IsCollectable => Recipe.ItemResult.Value?.AlwaysCollectable ?? false;
public bool IsCollectable => Recipe.ItemResult.ValueNullable?.AlwaysCollectable ?? false;
public IReadOnlyList<int?>? CollectableThresholds { get; }
public IReadOnlyList<(Item Item, int Amount)> Ingredients { get; }
public int MaxStartingQuality { get; }
@@ -28,11 +27,11 @@ public sealed record RecipeData
{
RecipeId = recipeId;
Recipe = LuminaSheets.RecipeSheet.GetRow(recipeId) ??
Recipe = LuminaSheets.RecipeSheet.TryGetRow(recipeId) ??
throw new ArgumentException($"Invalid recipe id {recipeId}", nameof(recipeId));
Table = Recipe.RecipeLevelTable.Value!;
ClassJob = (ClassJob)Recipe.CraftType.Row;
Table = Recipe.RecipeLevelTable.Value;
ClassJob = (ClassJob)Recipe.CraftType.RowId;
RecipeInfo = new()
{
IsExpert = Recipe.IsExpert,
@@ -48,49 +47,44 @@ public sealed record RecipeData
};
int[]? thresholds = null;
if (Recipe.CollectableMetadata is LazyRow<CollectablesShopRefine> { Value: { } row })
if (Recipe.CollectableMetadata.TryGetValue<CollectablesShopRefine>() is { } row)
thresholds = [row.LowCollectability, row.MidCollectability, row.HighCollectability];
else if (Recipe.CollectableMetadata is LazyRow<HWDCrafterSupply> { Value: { } row2 })
else if (Recipe.CollectableMetadata.TryGetValue<HWDCrafterSupply>() is { } row2)
{
foreach (var entry in row2.HWDCrafterSupplyParams)
{
if (entry.ItemTradeIn.Row == Recipe.ItemResult.Row)
if (entry.ItemTradeIn.RowId == Recipe.ItemResult.RowId)
{
thresholds = [entry.BaseCollectableRating, entry.MidCollectableRating, entry.HighCollectableRating];
break;
}
}
}
else if (Recipe.CollectableMetadata is LazyRow<SatisfactionSupply> { } row4)
else if (Recipe.CollectableMetadata.TryGetValue<SatisfactionSupply>() is { } row3)
{
var subRowCount = LuminaSheets.SatisfactionSupplySheet.GetSubRowCount(row4.Row);
if (subRowCount is { } subRowValue)
var subrowCount = LuminaSheets.SatisfactionSupplySheet.GetSubrowCount(row3.RowId);
for (ushort i = 0; i < subrowCount; ++i)
{
for (uint i = 0; i < subRowValue; ++i)
var subrow = LuminaSheets.SatisfactionSupplySheet.GetRow(row3.RowId, i);
if (subrow.Item.RowId == Recipe.ItemResult.RowId)
{
var subRow = LuminaSheets.SatisfactionSupplySheet.GetRow(row4.Row, i);
if (subRow == null)
continue;
if (subRow.Item.Row == Recipe.ItemResult.Row)
{
thresholds = [subRow.CollectabilityLow, subRow.CollectabilityMid, subRow.CollectabilityHigh];
break;
}
thresholds = [subrow.CollectabilityLow, subrow.CollectabilityMid, subrow.CollectabilityHigh];
break;
}
}
}
else if (Recipe.CollectableMetadata is LazyRow<SharlayanCraftWorksSupply> { Value: { } row5 })
else if (Recipe.CollectableMetadata.TryGetValue<SharlayanCraftWorksSupply>() is { } row5)
{
foreach (var item in row5.Item)
{
if (item.ItemId.Row == Recipe.ItemResult.Row)
if (item.ItemId.RowId == Recipe.ItemResult.RowId)
{
thresholds = [0, item.CollectabilityMid, item.CollectabilityHigh];
break;
}
}
}
else if (Recipe.CollectableMetadata is LazyRow<CollectablesRefine> { Value: { } row6 })
else if (Recipe.CollectableMetadata.TryGetValue<CollectablesRefine>() is { } row6)
{
if (row6.CollectabilityHigh != 0)
thresholds = [row6.CollectabilityLow, row6.CollectabilityMid, row6.CollectabilityHigh];
@@ -102,12 +96,12 @@ public sealed record RecipeData
Ingredients = Recipe.Ingredient.Zip(Recipe.AmountIngredient)
.Take(6)
.Where(i => i.First.Value != null)
.Select(i => (i.First.Value!, (int)i.Second))
.Where(i => i.First.IsValid)
.Select(i => (i.First.Value, (int)i.Second))
.ToList();
MaxStartingQuality = (int)Math.Floor(Recipe.MaterialQualityFactor * RecipeInfo.MaxQuality / 100f);
TotalHqILvls = (int)Ingredients.Where(i => i.Item.CanBeHq).Sum(i => i.Item.LevelItem.Row * i.Amount);
TotalHqILvls = (int)Ingredients.Where(i => i.Item.CanBeHq).Sum(i => i.Item.LevelItem.RowId * i.Amount);
}
public int CalculateItemStartingQuality(int itemIdx, int amount)
@@ -120,7 +114,7 @@ public sealed record RecipeData
if (!ingredient.Item.CanBeHq)
return 0;
var iLvls = ingredient.Item.LevelItem.Row * amount;
var iLvls = ingredient.Item.LevelItem.RowId * amount;
return (int)Math.Floor((float)iLvls / TotalHqILvls * MaxStartingQuality);
}
@@ -129,7 +123,7 @@ public sealed record RecipeData
if (TotalHqILvls == 0)
return 0;
var iLvls = Ingredients.Zip(hqQuantities).Sum(i => i.First.Item.LevelItem.Row * i.Second);
var iLvls = Ingredients.Zip(hqQuantities).Sum(i => i.First.Item.LevelItem.RowId * i.Second);
return (int)Math.Floor((float)iLvls / TotalHqILvls * MaxStartingQuality);
}
+25 -15
View File
@@ -12,7 +12,6 @@ using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using Dalamud.Utility;
using ImGuiNET;
using System;
using System.Collections.Generic;
@@ -23,6 +22,7 @@ using System.Threading;
using System.Threading.Tasks;
using Sim = Craftimizer.Simulator.Simulator;
using SimNoRandom = Craftimizer.Simulator.SimulatorNoRandom;
using Recipe = ExdSheets.Sheets.Recipe;
namespace Craftimizer.Windows;
@@ -376,7 +376,7 @@ public sealed class MacroEditor : Window, IDisposable
}
ImGui.SameLine(0, 5);
{
var manipLevel = ActionType.Manipulation.GetActionRow(RecipeData.ClassJob).Action!.ClassJobLevel;
var manipLevel = ActionType.Manipulation.GetActionRow(RecipeData.ClassJob).Action!.Value.ClassJobLevel;
using (var d = ImRaii.Disabled(manipLevel > CharacterStats.Level))
{
var v = CharacterStats.CanUseManipulation && manipLevel <= CharacterStats.Level;
@@ -586,7 +586,7 @@ public sealed class MacroEditor : Window, IDisposable
if (input.ItemId == 0)
return "None";
var name = LuminaSheets.ItemSheet.GetRow(input.ItemId)?.Name.ToDalamudString().ToString() ?? $"Unknown ({input.ItemId})";
var name = LuminaSheets.ItemSheet.TryGetRow(input.ItemId)?.Name.ExtractText() ?? $"Unknown ({input.ItemId})";
return input.IsHQ ? $"{name} (HQ)" : name;
}
@@ -727,6 +727,16 @@ public sealed class MacroEditor : Window, IDisposable
return (int)Math.Ceiling((y - b) / (c + 1));
}
private readonly struct RecipeWrapper(Recipe recipe) : IEquatable<RecipeWrapper>
{
public readonly Recipe Recipe = recipe;
public bool Equals(RecipeWrapper other) =>
Recipe.RowId == other.Recipe.RowId;
}
private readonly List<RecipeWrapper> searchableRecipes = LuminaSheets.RecipeSheet.Where(r => r.RecipeLevelTable.RowId != 0 && r.ItemResult.RowId != 0).Select(r => new RecipeWrapper(r)).ToList();
private bool DrawRecipeParams()
{
var oldStartingQuality = StartingQuality;
@@ -752,29 +762,29 @@ public sealed class MacroEditor : Window, IDisposable
(isExpert ? badgeSize.X + 3 : 0);
ImGui.AlignTextToFramePadding();
ImGui.Image(Service.IconManager.GetIconCached(RecipeData.Recipe.ItemResult.Value!.Icon).ImGuiHandle, new Vector2(imageSize));
ImGui.Image(Service.IconManager.GetIconCached(RecipeData.Recipe.ItemResult.Value.Icon).ImGuiHandle, new Vector2(imageSize));
ImGui.SameLine(0, 5);
ushort? newRecipe = null;
{
var recipe = RecipeData.Recipe;
var recipe = new RecipeWrapper(RecipeData.Recipe);
using var lockedFontHandle = AxisFont.Available ? AxisFont.Lock() : null;
var fontHandle = lockedFontHandle?.ImFont ?? ImGui.GetFont();
if (ImGuiUtils.SearchableCombo(
"combo",
ref recipe,
LuminaSheets.RecipeSheet.Where(r => r.RecipeLevelTable.Row != 0 && r.ItemResult.Row != 0),
searchableRecipes,
fontHandle,
ImGui.GetContentRegionAvail().X - rightSideWidth,
r => r.ItemResult.Value!.Name.ToDalamudString().ToString(),
r => r.RowId.ToString(),
r => r.Recipe.ItemResult.Value.Name.ExtractText(),
r => r.Recipe.RowId.ToString(),
r =>
{
ImGui.TextUnformatted($"{r.ItemResult.Value!.Name.ToDalamudString()}");
ImGui.TextUnformatted($"{r.Recipe.ItemResult.Value.Name.ExtractText()}");
var classJob = (ClassJob)r.CraftType.Row;
var textLevel = SqText.LevelPrefix.ToIconChar() + SqText.ToLevelString(r.RecipeLevelTable.Value!.ClassJobLevel);
var classJob = (ClassJob)r.Recipe.CraftType.RowId;
var textLevel = SqText.LevelPrefix.ToIconChar() + SqText.ToLevelString(r.Recipe.RecipeLevelTable.Value!.ClassJobLevel);
var textLevelSize = ImGui.CalcTextSize(textLevel);
ImGui.SameLine();
@@ -796,7 +806,7 @@ public sealed class MacroEditor : Window, IDisposable
ImGui.TextUnformatted(textLevel);
}))
{
newRecipe = (ushort)recipe.RowId;
newRecipe = (ushort)recipe.Recipe.RowId;
}
}
@@ -923,10 +933,10 @@ public sealed class MacroEditor : Window, IDisposable
{
var perItem = RecipeData.CalculateItemStartingQuality(idx, 1);
var total = RecipeData.CalculateItemStartingQuality(idx, hqCount);
ImGuiUtils.Tooltip($"{ingredient.Item.Name.ToDalamudString()} {SeIconChar.HighQuality.ToIconString()}\n+{perItem} Quality/Item{(total > 0 ? $"\n+{total} Quality" : "")}");
ImGuiUtils.Tooltip($"{ingredient.Item.Name.ExtractText()} {SeIconChar.HighQuality.ToIconString()}\n+{perItem} Quality/Item{(total > 0 ? $"\n+{total} Quality" : "")}");
}
else if (ingredient.Amount != 0)
ImGuiUtils.Tooltip($"{ingredient.Item.Name.ToDalamudString()}");
ImGuiUtils.Tooltip($"{ingredient.Item.Name.ExtractText()}");
}
ImGui.SameLine(0, 5);
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X - (5 + ImGui.CalcTextSize("/").X + 5 + ImGui.CalcTextSize($"99").X));
@@ -1137,7 +1147,7 @@ public sealed class MacroEditor : Window, IDisposable
{
var status = effect.Status();
using var _reset = ImRaii.DefaultFont();
ImGuiUtils.Tooltip($"{status.Name.ToDalamudString()}\n{status.Description.ToDalamudString()}");
ImGuiUtils.Tooltip($"{status.Name.ExtractText()}\n{status.Description.ExtractText()}");
}
ImGui.SameLine();
}
+13 -13
View File
@@ -527,7 +527,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
ImGuiUtils.TextCentered($"You do not have {RecipeData.ClassJob.GetName()} unlocked.");
ImGui.Separator();
var unlockQuest = RecipeData.ClassJob.GetUnlockQuest();
var (questGiver, questTerritory, questLocation, mapPayload) = ResolveLevelData(unlockQuest.IssuerLocation.Row);
var (questGiver, questTerritory, questLocation, mapPayload) = ResolveLevelData(unlockQuest.IssuerLocation.RowId);
var unlockText = $"Unlock it from {questGiver}";
ImGuiUtils.AlignCentered(ImGui.CalcTextSize(unlockText).X + 5 + ImGui.GetFrameHeight());
@@ -580,7 +580,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
case CraftableStatus.RequiredItem:
{
var item = RecipeData.Recipe.ItemRequired.Value!;
var itemName = item.Name.ToDalamudString().ToString();
var itemName = item.Name.ExtractText();
var imageSize = ImGui.GetFrameHeight();
ImGuiUtils.TextCentered($"You are missing the required equipment.");
@@ -594,7 +594,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
case CraftableStatus.RequiredStatus:
{
var status = RecipeData.Recipe.StatusRequired.Value!;
var statusName = status.Name.ToDalamudString().ToString();
var statusName = status.Name.ExtractText();
var statusIcon = Service.IconManager.GetIconCached(status.Icon);
var imageSize = new Vector2(ImGui.GetFrameHeight() * (statusIcon.AspectRatio ?? 1), ImGui.GetFrameHeight());
@@ -1073,16 +1073,16 @@ public sealed unsafe class RecipeNote : Window, IDisposable
return CraftableStatus.SpecialistRequired;
var itemRequired = RecipeData.Recipe.ItemRequired;
if (itemRequired.Row != 0 && itemRequired.Value != null)
if (itemRequired.RowId != 0 && itemRequired.IsValid)
{
if (!gearItems.Any(i => Gearsets.IsItem(i, itemRequired.Row)))
if (!gearItems.Any(i => Gearsets.IsItem(i, itemRequired.RowId)))
return CraftableStatus.RequiredItem;
}
var statusRequired = RecipeData.Recipe.StatusRequired;
if (statusRequired.Row != 0 && statusRequired.Value != null)
if (statusRequired.RowId != 0 && statusRequired.IsValid)
{
if (!Service.ClientState.LocalPlayer!.StatusList.Any(s => s.StatusId == statusRequired.Row))
if (!Service.ClientState.LocalPlayer!.StatusList.Any(s => s.StatusId == statusRequired.RowId))
return CraftableStatus.RequiredStatus;
}
@@ -1097,24 +1097,24 @@ public sealed unsafe class RecipeNote : Window, IDisposable
private static (string NpcName, string Territory, Vector2 MapLocation, MapLinkPayload Payload) ResolveLevelData(uint levelRowId)
{
var level = LuminaSheets.LevelSheet.GetRow(levelRowId) ??
var level = LuminaSheets.LevelSheet.TryGetRow(levelRowId) ??
throw new ArgumentNullException(nameof(levelRowId), $"Invalid level row {levelRowId}");
var territory = level.Territory.Value!.PlaceName.Value!.Name.ToDalamudString().ToString();
var territory = level.Territory.Value.PlaceName.Value.Name.ExtractText();
var location = WorldToMap2(new(level.X, level.Z), level.Map.Value!);
return (ResolveNpcResidentName(level.Object.Row), territory, location, new(level.Territory.Row, level.Map.Row, location.X, location.Y));
return (ResolveNpcResidentName(level.Object.RowId), territory, location, new(level.Territory.RowId, level.Map.RowId, location.X, location.Y));
}
private static Vector2 WorldToMap2(Vector2 worldCoordinates, ExdSheets.Map map)
private static Vector2 WorldToMap2(Vector2 worldCoordinates, ExdSheets.Sheets.Map map)
{
return MapUtil.WorldToMap(worldCoordinates, map.OffsetX, map.OffsetY, map.SizeFactor);
}
private static string ResolveNpcResidentName(uint npcRowId)
{
var resident = LuminaSheets.ENpcResidentSheet.GetRow(npcRowId) ??
var resident = LuminaSheets.ENpcResidentSheet.TryGetRow(npcRowId) ??
throw new ArgumentNullException(nameof(npcRowId), $"Invalid npc row {npcRowId}");
return resident.Singular.ToDalamudString().ToString();
return resident.Singular.ExtractText();
}
private static int? GetGearsetForJob(ClassJob job)
+1 -2
View File
@@ -10,7 +10,6 @@ using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.UI;
@@ -382,7 +381,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable
{
var status = effect.Status();
using var _reset = ImRaii.DefaultFont();
ImGuiUtils.Tooltip($"{status.Name.ToDalamudString()}\n{status.Description.ToDalamudString()}");
ImGuiUtils.Tooltip($"{status.Name.ExtractText()}\n{status.Description.ExtractText()}");
}
ImGui.SameLine();
}
+22 -13
View File
@@ -10,18 +10,21 @@
},
"ExdSheets": {
"type": "Direct",
"requested": "[1.2.2, )",
"resolved": "1.2.2",
"contentHash": "oS1oUBhlOpUWY1Wc3SwOLzfAMuSRzBn54I8p84euVUHrUEOzRZwA9vuNKNMAIY66eT1dpc/DxT+C7LNH0nK0jg==",
"requested": "[2.1.0, )",
"resolved": "2.1.0",
"contentHash": "SfvLFyL8LYsW4AzPLFVfFwtKPl9xegGraIe9oFar3IlWW8Z4kf5dkM+1CiSr/J+PQt4xt2QZc/ydZ4ibs3RosA==",
"dependencies": {
"Lumina": "3.15.2"
"Lumina": "4.1.1"
}
},
"Lumina": {
"type": "Direct",
"requested": "[3.15.2, )",
"resolved": "3.15.2",
"contentHash": "EnoxYEYMepcvAoXdZhaFJiv2aiDBIPjgkgzxR/+ArOxlrALzCgheTsb5yD39a9sxNIi2tNECT93ulZvYjx8fZg=="
"requested": "[4.1.1, )",
"resolved": "4.1.1",
"contentHash": "Hd+iTtdaPACTpViXaJ/+sQ3ZQ8MEpApCSD+mxTXnUTYDSZOAipuC4LsZqhAkLMeQHSK/R/jiXEXaXS7e0mTXyA==",
"dependencies": {
"Microsoft.Extensions.ObjectPool": "9.0.0-preview.1.24081.5"
}
},
"MathNet.Numerics": {
"type": "Direct",
@@ -31,14 +34,20 @@
},
"Meziantou.Analyzer": {
"type": "Direct",
"requested": "[2.0.162, )",
"resolved": "2.0.162",
"contentHash": "lU5ZkiNx6Jj++yYhkUkn2qsgl+PSfAy+BDFc0IkoVVeSCnmUOGBa0Eb1XzGLAeyAuIoz6vYN4J97Q/uiGdIkhw=="
"requested": "[2.0.163, )",
"resolved": "2.0.163",
"contentHash": "vN0YmOkuvPLukMsefLHYCWYaLPzpc6SfoR74aPwuLeK8QdxgxkavywQ1q/II0shLEEaN1RhlMjmL1RxMPW853w=="
},
"Microsoft.Extensions.ObjectPool": {
"type": "Direct",
"requested": "[9.0.0-preview.1.24081.5, )",
"resolved": "9.0.0-preview.1.24081.5",
"contentHash": "aAR7YW+pUUdvHk3vj7GtAi71dWGDIuY9270lsmQ6lKw23zzY+r8pLP3cGNbJdlnA9VWl+S+gnIVkBCqj2ROlEg=="
},
"DotNext": {
"type": "Transitive",
"resolved": "5.8.0",
"contentHash": "5PwF7lUwgJKMcQRrMnFo8ilqrFq9OyaQ5Lq/zFHn0LahhLriNeySCPs08Zd15FdBV0G0KpZvPHBC8Rp1LIsrhg==",
"resolved": "5.11.0",
"contentHash": "aLWtURne05gwWFFsOg9/X1g4V5yHyuWHX5paQIN7pJIDLCbaCDHcQlLeRRvzvksjAflZJ7tTHkowN/Xi1NXPrA==",
"dependencies": {
"System.IO.Hashing": "8.0.0"
}
@@ -55,7 +64,7 @@
"type": "Project",
"dependencies": {
"Craftimizer.Simulator": "[1.0.0, )",
"DotNext": "[5.8.0, )"
"DotNext": "[5.11.0, )"
}
}
}
+1 -1
View File
@@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.162">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
+2 -2
View File
@@ -10,8 +10,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DotNext" Version="5.8.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.162">
<PackageReference Include="DotNext" Version="5.11.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
+1 -1
View File
@@ -11,7 +11,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.162">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>