using EFT.InventoryLogic; using SPT.Reflection.Utils; using System.Text; using KeycardTemplate = GClass2623; using ArmorTemplate = GClass2550; using ArmoredRigTemplate = GClass2602; using MagazineTemplate = GClass2586; namespace LootValueEX.Extensions { internal static class ItemExtensions { /// /// Checks if an item has been examined by the player. /// /// 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. /// /// The item to retrieve the attribute from. /// The ID of the attribute to retrieve. /// The value of the attribute, or -1f if the item is null or the attribute is not found. internal static float GetItemAttribute(this Item? item, EItemAttributeId attributeId) { if (item == null) return -1f; try { return item.Attributes.Single(att => att.Id.Equals(attributeId)).Base(); } catch (InvalidOperationException) { return -1f; } } /// /// 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 async Task GetCustomHashAsync(this Item? item) { if (item == null) return string.Empty; StringBuilder prehashString = new StringBuilder(); 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.DoMap(s => s.Items.DoMap(i => prehashString.Append(i.PrehashTemplate()))); } 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) { if (item == null) return String.Empty; if (item.Attributes.IsNullOrEmpty()) return String.Empty; StringBuilder sb = new StringBuilder(); item.Attributes.ForEach(attr => sb.Append($"\n{attr.Id}\n\tName: {attr.Name}\n\tBase Value: {attr.Base()}\n\tString value: {attr.StringValue()}\n\tDisplay Type: {attr.DisplayType()}")); return sb.ToString(); } #endif /// /// Retrieves the durability of a given item. /// /// This function takes an optional Item as a parameter and returns its durability. /// If the item is null, it returns -1f. The durability is determined by the item's template. /// /// The item to retrieve the durability for. /// The durability of the item, or -1f if the item is null. internal static float GetDurability(this Item? item) { if (item == null) return -1f; switch (item.Template) { case ArmoredRigTemplate armoredRig: case ArmorTemplate armor: return Utils.ItemUtils.GetArmorDurability(item.GetItemComponentsInChildren(true)); default: return item.GetItemAttribute(EItemAttributeId.Durability); } } /// /// Retrieves the number of uses remaining for a given item. /// /// This function takes an optional Item as a parameter and returns the number of uses remaining. /// If the item is null, it returns -1f. The number of uses is determined by the item's template. /// /// The item to retrieve the number of uses for. /// The number of uses remaining for the item, or -1f if the item is null. internal static float GetUses(this Item? item) { if (item == null) return -1f; switch (item.Template) { case KeycardTemplate: KeyComponent keyComponent = item.GetItemComponent(); return keyComponent.Template.MaximumNumberOfUsage - keyComponent.NumberOfUsages; case Meds2Class: if (item.TryGetItemComponent(out MedKitComponent medKitComponent)) return medKitComponent.HpResource; return -1f; case MagazineTemplate: MagazineClass? magazineClass = item as MagazineClass; return magazineClass?.Count ?? -1f; case AmmoBoxTemplate: AmmoBox? ammoBox = item as AmmoBox; return ammoBox?.Count ?? -1f; default: return -1f; } } } }