diff --git a/Plugin/Extensions/ItemExtensions.cs b/Plugin/Extensions/ItemExtensions.cs
index 28f0f97..f0b8cce 100644
--- a/Plugin/Extensions/ItemExtensions.cs
+++ b/Plugin/Extensions/ItemExtensions.cs
@@ -16,8 +16,23 @@ namespace LootValueEX.Extensions
/// The item to check.
/// True if the item has been examined, false otherwise.
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;
+ }
+
///
/// Retrieves the value of a specific attribute from an item.
///
diff --git a/Plugin/Patches/Screens/InventoryScreenPatch.cs b/Plugin/Patches/Screens/InventoryScreenPatch.cs
index e25eea4..7ed2a93 100644
--- a/Plugin/Patches/Screens/InventoryScreenPatch.cs
+++ b/Plugin/Patches/Screens/InventoryScreenPatch.cs
@@ -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);
diff --git a/Plugin/Patches/Tooltips/TooltipPatch.cs b/Plugin/Patches/Tooltips/TooltipPatch.cs
index 66e5968..1e48904 100644
--- a/Plugin/Patches/Tooltips/TooltipPatch.cs
+++ b/Plugin/Patches/Tooltips/TooltipPatch.cs
@@ -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 += $"
TemplateID: {GridItemTooltipPatch.HoveredItem?.TemplateId}
Template: {GridItemTooltipPatch.HoveredItem?.Template}
Item hashsum: {GridItemTooltipPatch.HoveredItem?.GetHashSum()}
Custom hash: {GridItemTooltipPatch.HoveredItem?.GetCustomHash()}
Item durability: {GridItemTooltipPatch.HoveredItem?.GetDurability()}
Item uses: {GridItemTooltipPatch.HoveredItem?.GetUses()}
GridItemView";
- Plugin.Log.LogDebug(GridItemTooltipPatch.HoveredItem?.AttributesToString());
+ Structs.TradeOfferStruct tradeOffer = Utils.ItemUtils.GetBestTraderValue(GridItemTooltipPatch.HoveredItem);
+ text += $"
Hash: {GridItemTooltipPatch.HoveredItem?.GetCustomHash()}
Trader: {tradeOffer.TraderID}
Value: {tradeOffer.Price}
Currency: {tradeOffer.CurrencyID}
Price in rubles: {tradeOffer.PriceInRouble}
GridItemView";
}
if (InsuranceSlotPatch.PatchTooltip)
{
diff --git a/Plugin/Patches/TraderClassPatch.cs b/Plugin/Patches/TraderClassPatch.cs
new file mode 100644
index 0000000..1dc2471
--- /dev/null
+++ b/Plugin/Patches/TraderClassPatch.cs
@@ -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);
+ }
+ }
+}
diff --git a/Plugin/Plugin.cs b/Plugin/Plugin.cs
index aaffaeb..84770b1 100644
--- a/Plugin/Plugin.cs
+++ b/Plugin/Plugin.cs
@@ -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();
diff --git a/Plugin/Structs/TradeOfferStruct.cs b/Plugin/Structs/TradeOfferStruct.cs
new file mode 100644
index 0000000..52b7091
--- /dev/null
+++ b/Plugin/Structs/TradeOfferStruct.cs
@@ -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;
+ }
+ }
+}
diff --git a/Plugin/Utils/EconomyUtils.cs b/Plugin/Utils/EconomyUtils.cs
new file mode 100644
index 0000000..6a02515
--- /dev/null
+++ b/Plugin/Utils/EconomyUtils.cs
@@ -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.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;
+ }
+ }
+}
diff --git a/Plugin/Utils/ItemUtils.cs b/Plugin/Utils/ItemUtils.cs
index 012ff5a..bb2daa2 100644
--- a/Plugin/Utils/ItemUtils.cs
+++ b/Plugin/Utils/ItemUtils.cs
@@ -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 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;
}
}