forked from aly/qstbak
110 lines
4 KiB
C#
110 lines
4 KiB
C#
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using Dalamud.Plugin.Services;
|
|
using LLib.GameData;
|
|
using LLib.Shop;
|
|
using LLib.Shop.Model;
|
|
using Lumina.Excel.Sheets;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Questionable.Controller.CustomDelivery;
|
|
|
|
internal sealed class VendorResolverService(IDataManager dataManager, VendorResolver vendorResolver, NpcPositionCache npcPositionCache, ILogger<VendorResolverService> logger)
|
|
{
|
|
internal readonly record struct IngredientInfo(uint ItemId, int CountPerCraft);
|
|
|
|
internal readonly record struct RecipeInfo(uint RecipeId, uint CraftedItemId, IReadOnlyList<IngredientInfo> Ingredients, EClassJob CraftingClass);
|
|
|
|
internal readonly record struct VendorInfo(uint ShopId, uint VendorNpcId, ushort TerritoryId, Vector3 Position, int DialogOptionIndex);
|
|
|
|
public RecipeInfo? ResolveRecipe(uint craftedItemId, EClassJob? preferredJob = null)
|
|
{
|
|
if (!dataManager.GetExcelSheet<RecipeLookup>().TryGetRow(craftedItemId, out var row))
|
|
{
|
|
logger.LogDebug("No RecipeLookup row for item {ItemId}", craftedItemId);
|
|
return null;
|
|
}
|
|
(EClassJob, uint)[] array = new(EClassJob, uint)[8]
|
|
{
|
|
(EClassJob.Carpenter, row.CRP.RowId),
|
|
(EClassJob.Blacksmith, row.BSM.RowId),
|
|
(EClassJob.Armorer, row.ARM.RowId),
|
|
(EClassJob.Goldsmith, row.GSM.RowId),
|
|
(EClassJob.Leatherworker, row.LTW.RowId),
|
|
(EClassJob.Weaver, row.WVR.RowId),
|
|
(EClassJob.Alchemist, row.ALC.RowId),
|
|
(EClassJob.Culinarian, row.CUL.RowId)
|
|
};
|
|
(EClassJob, uint)[] array2;
|
|
if (preferredJob.HasValue)
|
|
{
|
|
array2 = array;
|
|
for (int i = 0; i < array2.Length; i++)
|
|
{
|
|
var (eClassJob, num) = array2[i];
|
|
if (eClassJob == preferredJob.Value && num != 0)
|
|
{
|
|
if (!dataManager.GetExcelSheet<Recipe>().TryGetRow(num, out var row2))
|
|
{
|
|
break;
|
|
}
|
|
List<IngredientInfo> list = CollectIngredients(row2);
|
|
if (list.Count == 0)
|
|
{
|
|
break;
|
|
}
|
|
logger.LogDebug("Resolved recipe {RecipeId} ({ClassJob}) for item {ItemId} via preferred job: {Count} ingredient(s)", num, eClassJob, craftedItemId, list.Count);
|
|
return new RecipeInfo(num, craftedItemId, list, eClassJob);
|
|
}
|
|
}
|
|
}
|
|
array2 = array;
|
|
for (int i = 0; i < array2.Length; i++)
|
|
{
|
|
var (eClassJob2, num2) = array2[i];
|
|
if (num2 != 0 && dataManager.GetExcelSheet<Recipe>().TryGetRow(num2, out var row3))
|
|
{
|
|
List<IngredientInfo> list2 = CollectIngredients(row3);
|
|
if (list2.Count != 0)
|
|
{
|
|
logger.LogDebug("Resolved recipe {RecipeId} ({ClassJob}) for item {ItemId}: {Count} ingredient(s)", num2, eClassJob2, craftedItemId, list2.Count);
|
|
return new RecipeInfo(num2, craftedItemId, list2, eClassJob2);
|
|
}
|
|
}
|
|
}
|
|
logger.LogDebug("No valid recipe found for item {ItemId}", craftedItemId);
|
|
return null;
|
|
}
|
|
|
|
public VendorInfo? ResolveVendor(uint ingredientId)
|
|
{
|
|
if (!npcPositionCache.IsBuilt)
|
|
{
|
|
logger.LogWarning("NPC position cache not built yet, cannot resolve a vendor for ingredient {IngredientId}", ingredientId);
|
|
return null;
|
|
}
|
|
ShopSearchResult shopSearchResult = vendorResolver.FindGilVendor(ingredientId);
|
|
if (shopSearchResult == null)
|
|
{
|
|
logger.LogDebug("No vendor with known position found for ingredient {IngredientId}", ingredientId);
|
|
return null;
|
|
}
|
|
logger.LogDebug("Found vendor NPC {NpcId} selling ingredient {IngredientId} at shop {ShopId} in territory {TerritoryId} (dialog option {DialogOption})", shopSearchResult.NpcId, ingredientId, shopSearchResult.ShopId, shopSearchResult.TerritoryId, shopSearchResult.DialogOptionIndex);
|
|
return new VendorInfo(shopSearchResult.ShopId, shopSearchResult.NpcId, shopSearchResult.TerritoryId, shopSearchResult.NpcPosition, shopSearchResult.DialogOptionIndex);
|
|
}
|
|
|
|
private static List<IngredientInfo> CollectIngredients(Recipe recipe)
|
|
{
|
|
List<IngredientInfo> list = new List<IngredientInfo>();
|
|
for (int i = 0; i < recipe.Ingredient.Count; i++)
|
|
{
|
|
uint rowId = recipe.Ingredient[i].RowId;
|
|
int num = recipe.AmountIngredient[i];
|
|
if (rowId != 0 && num > 0)
|
|
{
|
|
list.Add(new IngredientInfo(rowId, num));
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
}
|