feat: get best trader offer for items

TODO: Make a better conversion for USD/EUR to RUB
This commit is contained in:
Yui 2024-11-08 17:17:10 -03:00
parent a86213d3a6
commit db4003caa7
Signed by: yui
GPG Key ID: F368D23A0ABA04B4
8 changed files with 132 additions and 6 deletions

View File

@ -16,8 +16,23 @@ namespace LootValueEX.Extensions
/// <param name="item">The item to check.</param>
/// <returns>True if the item has been examined, false otherwise.</returns>
internal static bool IsExamined(this Item? item) => item != null && ClientAppUtils.GetMainApp().GetClientBackEndSession().Profile.Examined(item);
internal static bool IsStacked(this Item? item) => item != null && (item.StackObjectsCount > 1 || item.UnlimitedCount);
internal static string PrehashTemplate(this Item? item) => string.Format("{0}|{1}|{2}", item?.TemplateId, item.GetDurability(), item.GetUses());
internal static Item? UnstackItem(this Item? item)
{
if (item == null)
return null;
if (!item.IsStacked())
return item;
Item? itemClone = item.CloneItem();
itemClone.StackObjectsCount = 1;
itemClone.UnlimitedCount = false;
return itemClone;
}
/// <summary>
/// Retrieves the value of a specific attribute from an item.
/// </summary>

View File

@ -25,7 +25,8 @@ namespace LootValueEX.Patches.Screens
Stopwatch sw = Stopwatch.StartNew();
foreach(EFT.InventoryLogic.Item item in profile.Inventory.GetPlayerItems(EFT.InventoryLogic.EPlayerItems.Equipment))
{
Plugin.Log.LogDebug($"Equip Process: {item.LocalizedName()} ({item.TemplateId}): {await item.GetCustomHashAsync()}");
//Plugin.Log.LogDebug($"Equip Process: {item.LocalizedName()} ({item.TemplateId}): {await item.GetCustomHashAsync()}");
continue;
}
sw.Stop();
Plugin.Log.LogDebug($"Equipment processing finished in {sw.ElapsedMilliseconds}ms");
@ -43,7 +44,8 @@ namespace LootValueEX.Patches.Screens
Stopwatch sw = Stopwatch.StartNew();
foreach (EFT.InventoryLogic.Item item in lootItemClass.GetAllItems())
{
Plugin.Log.LogDebug($"LootItemClass process: {item.LocalizedName()} ({item.TemplateId}): {await item.GetCustomHashAsync()}");
//Plugin.Log.LogDebug($"LootItemClass process: {item.LocalizedName()} ({item.TemplateId}): {await item.GetCustomHashAsync()}");
continue;
}
Plugin.Log.LogDebug($"LootItemClass processing finished in {sw.ElapsedMilliseconds}ms");
tcsLoot.SetResult(true);

View File

@ -19,12 +19,10 @@ namespace LootValueEX.Patches.Tooltips
[PatchPostfix]
public static void AlterText(SimpleTooltip __instance, string text)
{
StackTrace stackTrace = new StackTrace();
Plugin.Log.LogDebug("Stacktrace of tooltip call: \n" + stackTrace.ToString());
if (GridItemTooltipPatch.PatchTooltip)
{
text += $"<br>TemplateID: {GridItemTooltipPatch.HoveredItem?.TemplateId}<br>Template: {GridItemTooltipPatch.HoveredItem?.Template}<br>Item hashsum: {GridItemTooltipPatch.HoveredItem?.GetHashSum()}<br>Custom hash: {GridItemTooltipPatch.HoveredItem?.GetCustomHash()}<br>Item durability: {GridItemTooltipPatch.HoveredItem?.GetDurability()}<br>Item uses: {GridItemTooltipPatch.HoveredItem?.GetUses()}<br><color=#ff0fff><b>GridItemView</b></color>";
Plugin.Log.LogDebug(GridItemTooltipPatch.HoveredItem?.AttributesToString());
Structs.TradeOfferStruct tradeOffer = Utils.ItemUtils.GetBestTraderValue(GridItemTooltipPatch.HoveredItem);
text += $"<br>Hash: {GridItemTooltipPatch.HoveredItem?.GetCustomHash()}<br>Trader: {tradeOffer.TraderID}<br>Value: {tradeOffer.Price}<br>Currency: {tradeOffer.CurrencyID}<br>Price in rubles: {tradeOffer.PriceInRouble}<br><color=#ff0fff><b>GridItemView</b></color>";
}
if (InsuranceSlotPatch.PatchTooltip)
{

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using SPT.Reflection.Patching;
namespace LootValueEX.Patches
{
internal class TraderClassPatch : ModulePatch
{
protected override MethodBase GetTargetMethod() => typeof(TraderClass).GetConstructors().First();
[PatchPostfix]
private static void GenerateSupplyData(ref TraderClass __instance)
{
Plugin.Log.LogDebug($"Generating Assortment Data for trader {__instance.Id}");
__instance.RefreshAssortment(true, false);
}
}
}

View File

@ -11,6 +11,8 @@ namespace LootValueEX
{
Log = base.Logger;
new Patches.TraderClassPatch().Enable();
new Patches.Tooltips.GridItemTooltipPatch().Enable();
new Patches.Tooltips.TooltipPatch().Enable();
new Patches.Tooltips.InsuranceGridPatch().Enable();

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LootValueEX.Structs
{
internal readonly struct TradeOfferStruct
{
internal readonly string TraderID;
internal readonly string CurrencyID;
internal readonly int Price;
internal readonly float PriceInRouble;
internal TradeOfferStruct(string traderId, string currencyId, int price, float priceInRouble)
{
TraderID = traderId;
CurrencyID = currencyId;
Price = price;
PriceInRouble = priceInRouble;
}
}
}

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Comfort.Common;
using EFT.InventoryLogic;
using SPT.Reflection.Utils;
using EFTCurrencyUtils = GClass2531;
namespace LootValueEX.Utils
{
internal class EconomyUtils
{
public static float ConvertToRuble(string id, float amount)
{
if (!EFTCurrencyUtils.TryGetCurrencyType(id, out ECurrencyType currencyType))
return 0f;
if (currencyType.Equals(ECurrencyType.RUB))
return amount;
return amount * (float)Singleton<HandbookClass>.Instance.GetBasePrice(id);
}
public static Structs.TradeOfferStruct GetTraderItemOffer(TraderClass trader, Item item)
{
Plugin.Log.LogDebug($"GetTraderItemOffer: {item.LocalizedName()} - {trader.LocalizedName}");
TraderClass.GStruct244? tradeOffer = trader.GetUserItemPrice(item);
if (tradeOffer == null)
{
Plugin.Log.LogDebug("GetTraderItemOffer: tradeOffer == null");
return default;
}
if(tradeOffer.Value.Amount > 0)
{
Plugin.Log.LogDebug($"{trader.LocalizedName}\n\tCurrencyID: {tradeOffer.Value.CurrencyId}\n\tValue: {tradeOffer.Value.Amount}\n\tPrice in RB: {EconomyUtils.ConvertToRuble(tradeOffer.Value.CurrencyId, tradeOffer.Value.Amount)}");
return new Structs.TradeOfferStruct(trader.Id, tradeOffer.Value.CurrencyId, tradeOffer.Value.Amount, EconomyUtils.ConvertToRuble(tradeOffer.Value.CurrencyId, tradeOffer.Value.Amount));
}
Plugin.Log.LogDebug("GetTraderItemOffer: no value");
return default;
}
}
}

View File

@ -1,4 +1,6 @@
using EFT.InventoryLogic;
using LootValueEX.Extensions;
using SPT.Reflection.Utils;
namespace LootValueEX.Utils
{
@ -13,5 +15,23 @@ namespace LootValueEX.Utils
}
return totalDurability;
}
public static Task<Structs.TradeOfferStruct> GetBestTraderValueAsync(Item item)
{
Structs.TradeOfferStruct bestOffer = new();
item = item.UnstackItem();
foreach (TraderClass trader in ClientAppUtils.GetMainApp().GetClientBackEndSession().DisplayableTraders)
{
Structs.TradeOfferStruct currentOffer = EconomyUtils.GetTraderItemOffer(trader, item);
if (currentOffer.Equals(default) || currentOffer.Price <= 0)
continue;
if (currentOffer.PriceInRouble > bestOffer.PriceInRouble)
bestOffer = currentOffer;
}
return Task.FromResult(bestOffer);
}
public static Structs.TradeOfferStruct GetBestTraderValue(Item item) => Task.Run(() => GetBestTraderValueAsync(item)).Result;
}
}