From a86213d3a64f9c29f24ce265103a5c69ac7a4827 Mon Sep 17 00:00:00 2001 From: Yui Date: Wed, 6 Nov 2024 17:45:58 -0300 Subject: [PATCH] feat: async inventory processing TODO: Do !!NOT!! process containers twice! --- Plugin/Extensions/ItemExtensions.cs | 18 +++++---- .../Patches/Screens/InventoryScreenPatch.cs | 39 +++++++++++++++++-- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/Plugin/Extensions/ItemExtensions.cs b/Plugin/Extensions/ItemExtensions.cs index 6efcba7..28f0f97 100644 --- a/Plugin/Extensions/ItemExtensions.cs +++ b/Plugin/Extensions/ItemExtensions.cs @@ -16,7 +16,8 @@ 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 string PrehashTemplate(this Item? item) => string.Format("{0}|{1}|{2}", item?.TemplateId, item.GetDurability(), item.GetUses()); + /// /// Retrieves the value of a specific attribute from an item. /// @@ -39,27 +40,28 @@ namespace LootValueEX.Extensions /// /// Generates a custom hash for the given item. - /// + /// /// This function takes an optional Item as a parameter and returns its custom hash. /// If the item is null, it returns an empty string. The custom hash is determined by the item's template, durability, and uses. /// /// The item to retrieve the custom hash for. /// The custom hash of the item, or an empty string if the item is null. - internal static string GetCustomHash(this Item? item) + internal static async Task GetCustomHashAsync(this Item? item) { if (item == null) return string.Empty; - StringBuilder prehashString = new StringBuilder(); - item.GetAllItems().Where(prop => !prop.Equals(item)).ExecuteForEach(prop => prehashString.Append(prop.GetCustomHash())); + + item.GetAllItems().Where(i => !i.Equals(item)).DoMap(i => prehashString.Append(i.PrehashTemplate())); if (item.Template.Equals(typeof(MagazineTemplate))) { MagazineTemplate magTemplate = (MagazineTemplate)item.Template; - magTemplate.Cartridges.ExecuteForEach(prop => prop.Items.ExecuteForEach(ammo => prehashString.Append(ammo.GetCustomHash()))); + magTemplate.Cartridges.DoMap(s => s.Items.DoMap(i => prehashString.Append(i.PrehashTemplate()))); } - string itemHashTemplate = string.Format("{0}|{1}|{2}|{3}", prehashString.ToString(), item.TemplateId, item.GetDurability(), item.GetUses()); - return Utils.HashingUtils.ConvertToSha256(itemHashTemplate); + prehashString.Append(item.PrehashTemplate()); + return await Task.Run(() => Utils.HashingUtils.ConvertToSha256(prehashString.ToString())); } + internal static string GetCustomHash(this Item? item) => Task.Run(() => item?.GetCustomHashAsync()).Result ?? string.Empty; #if DEBUG internal static string AttributesToString(this Item? item) { diff --git a/Plugin/Patches/Screens/InventoryScreenPatch.cs b/Plugin/Patches/Screens/InventoryScreenPatch.cs index 03baf33..e25eea4 100644 --- a/Plugin/Patches/Screens/InventoryScreenPatch.cs +++ b/Plugin/Patches/Screens/InventoryScreenPatch.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using System.Diagnostics; +using System.Reflection; using EFT; using EFT.HealthSystem; using EFT.UI; @@ -14,10 +15,40 @@ namespace LootValueEX.Patches.Screens [PatchPostfix] private static void PatchPostfix(ref Profile ___profile_0, ref LootItemClass ___lootItemClass) { - ___profile_0.Inventory.GetPlayerItems(EFT.InventoryLogic.EPlayerItems.Equipment).ExecuteForEach(item => Plugin.Log.LogDebug($"{item.LocalizedName()} ({item.TemplateId}): {item.GetCustomHash()}")); - + Profile profile = ___profile_0; + + TaskCompletionSource tcsInventory = new(); + CancellationTokenSource ctsInventory = new CancellationTokenSource(5000); + Task taskInventory = tcsInventory.Task; + Task.Factory.StartNew(async () => + { + 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()}"); + } + sw.Stop(); + Plugin.Log.LogDebug($"Equipment processing finished in {sw.ElapsedMilliseconds}ms"); + tcsInventory.SetResult(true); + }, ctsInventory.Token); + if(___lootItemClass != null) - ___lootItemClass.GetAllItems().ExecuteForEach(item => Plugin.Log.LogDebug($"{item.LocalizedName()} ({item.TemplateId}): {item.GetCustomHash()}")); + { + LootItemClass lootItemClass = ___lootItemClass; + TaskCompletionSource tcsLoot = new(); + CancellationTokenSource ctsLoot = new CancellationTokenSource(5000); + Task taskLoot = tcsLoot.Task; + Task.Factory.StartNew(async () => + { + 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 processing finished in {sw.ElapsedMilliseconds}ms"); + tcsLoot.SetResult(true); + }, ctsLoot.Token); + } } } }