diff --git a/Patches/ContextMenuPatches.cs b/Patches/ContextMenuPatches.cs index 2a0cc84..e5d5532 100644 --- a/Patches/ContextMenuPatches.cs +++ b/Patches/ContextMenuPatches.cs @@ -38,6 +38,8 @@ public static class ContextMenuPatches new DisableLoadPresetOnBulletsPatch().Enable(); + new EmptyModSlotMenuPatch().Enable(); + new EmptyModSlotMenuRemovePatch().Enable(); new EmptySlotMenuPatch().Enable(); new EmptySlotMenuRemovePatch().Enable(); } @@ -383,7 +385,7 @@ public static class ContextMenuPatches } } - public class EmptySlotMenuPatch : ModulePatch + public class EmptyModSlotMenuPatch : ModulePatch { protected override MethodBase GetTargetMethod() { @@ -403,7 +405,7 @@ public static class ContextMenuPatches } } - public class EmptySlotMenuRemovePatch : ModulePatch + public class EmptyModSlotMenuRemovePatch : ModulePatch { protected override MethodBase GetTargetMethod() { @@ -421,6 +423,45 @@ public static class ContextMenuPatches } } + public class EmptySlotMenuPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + // SetSlotGraphics is called with false both during setup and when an item is removed + return AccessTools.DeclaredMethod(typeof(SlotView), nameof(SlotView.SetSlotGraphics)); + } + + [PatchPostfix] + public static void Postfix(SlotView __instance, bool fullSlot, ItemUiContext ___ItemUiContext) + { + if (!Settings.EnableSlotSearch.Value || fullSlot) + { + return; + } + + EmptySlotMenuTrigger menuTrigger = __instance.GetOrAddComponent(); + menuTrigger.Init(__instance.Slot, __instance.ParentItemContext, ___ItemUiContext); + } + } + + public class EmptySlotMenuRemovePatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.DeclaredMethod(typeof(SlotView), nameof(SlotView.SetupItemView)); + } + + [PatchPostfix] + public static void Postfix(SlotView __instance) + { + EmptySlotMenuTrigger menuTrigger = __instance.GetComponent(); + if (menuTrigger != null) + { + UnityEngine.Object.Destroy(menuTrigger); + } + } + } + public class PositionSubMenuPatch : ModulePatch { protected override MethodBase GetTargetMethod() diff --git a/Patches/FleaPrevSearchPatches.cs b/Patches/FleaPrevSearchPatches.cs index 41fdb38..baa031a 100644 --- a/Patches/FleaPrevSearchPatches.cs +++ b/Patches/FleaPrevSearchPatches.cs @@ -373,30 +373,35 @@ public static class FleaPrevSearchPatches if (Settings.AutoExpandCategories.Value) { + Transform scrollArea = __instance.transform.Find("CategoriesPanel/ScrollArea"); + // Try to auto-expand categories to use available space. Gotta do math to see what fits - const int PanelHeight = 780; - const int CategoryHeight = 34; - const int SubcategoryHeight = 25; + float PanelHeight = scrollArea.RectTransform().sizeDelta.y * scrollArea.lossyScale.y; // 780; + float CategoryHeight = 36f * scrollArea.lossyScale.y; + float SubcategoryHeight = 25f * scrollArea.lossyScale.y; var activeCategories = __instance.GetComponentsInChildren(); var activeSubcategories = __instance.GetComponentsInChildren(); - int currentHeight = activeCategories.Length * CategoryHeight + activeSubcategories.Length * SubcategoryHeight; + float currentHeight = activeCategories.Length * CategoryHeight + activeSubcategories.Length * SubcategoryHeight; var categories = __instance.GetComponentsInChildren() .Where(cv => cv.transform.childCount > 0) .Select(cv => cv.transform.GetChild(0).GetComponent()) .Where(c => c != null && c.gameObject.activeInHierarchy); + int categoryTrees = 0; while (categories.Any()) { + categoryTrees = Math.Max(categoryTrees, categories.Count()); + // This is all child categories that aren't already open; have matching *offers* (x.Count); and if they have children themselves they're a category, otherwise a subcategory - int additionalHeight = categories + float additionalHeight = categories .Where(c => !c.R().IsOpen && c.Node != null) .SelectMany(c => c.Node.Children) .Where(n => n.Count > 0) .Sum(n => n.Children.Any() ? CategoryHeight : SubcategoryHeight); - if (currentHeight + additionalHeight > PanelHeight) + if (categoryTrees > 1 && currentHeight + additionalHeight > PanelHeight) { break; } diff --git a/Patches/FleaSlotSearchPatches.cs b/Patches/FleaSlotSearchPatches.cs index ad11a03..4c7f0af 100644 --- a/Patches/FleaSlotSearchPatches.cs +++ b/Patches/FleaSlotSearchPatches.cs @@ -1,4 +1,5 @@ -using EFT.UI.Ragfair; +using EFT.HandBook; +using EFT.UI.Ragfair; using HarmonyLib; using SPT.Reflection.Patching; using System.Linq; @@ -32,7 +33,27 @@ public static class FleaSlotSearchPatches if (search != null) { __state = search.StringValue.Split(':')[0]; - ___handbookClass[__state].Data.Id = search.StringValue; + EntityNodeClass node = ___handbookClass[__state]; + if (node != null) + { + // If the id is in the handbook (any mod slots on actual items), + // fake out the id so the filter is generated with the slot suffix + node.Data.Id = search.StringValue; + } + else + { + // If the id is not, like equipment slots, inject a dummy node + HandbookData dummyData = new HandbookData() + { + Id = search.StringValue + }; + EntityNodeClass dummyNode = new EntityNodeClass() + { + Data = dummyData, + IsDummy = true + }; + ___handbookClass.StructuredItems.AddVirtual(__state, dummyNode); + } searches[searches.IndexOf(search)] = new(EFilterType.LinkedSearch, __state, search.Add); } } @@ -47,7 +68,17 @@ public static class FleaSlotSearchPatches if (__state != null) { - ___handbookClass[__state].Data.Id = __state; + EntityNodeClass node = ___handbookClass[__state]; + if (node.IsDummy) + { + // We injected this dummy node, remove it + ___handbookClass.StructuredItems.RemoveVirtual(__state); + } + else + { + // Restore the Id back to its normal value + node.Data.Id = __state; + } } } } diff --git a/UIFixes.csproj b/UIFixes.csproj index 430777d..29833eb 100644 --- a/UIFixes.csproj +++ b/UIFixes.csproj @@ -4,7 +4,7 @@ net471 Tyfon.UIFixes SPT UI Fixes - 2.1.1 + 2.1.2 true latest Debug;Release;Dist @@ -95,8 +95,8 @@ if $(ConfigurationName) == Dist ( mkdir "$(ProjectDir)\dist\BepInEx\plugins" xcopy /F /Y "$(TargetPath)" "$(ProjectDir)\dist\BepInEx\plugins\" - 7z a -t7z Tyfon-UIFixes-$(Version).7z $(ProjectDir)\dist\BepInEx $(ProjectDir)\dist\user - move /Y Tyfon-UIFixes-$(Version).7z dist\ + 7z a -t7z $(TargetName.Replace(".", "-"))-$(Version).7z $(ProjectDir)\dist\BepInEx $(ProjectDir)\dist\user + move /Y $(TargetName.Replace(".", "-"))-$(Version).7z dist\ )' /> diff --git a/server/package.json b/server/package.json index 8e18315..540b526 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "uifixes", - "version": "2.1.1", + "version": "2.1.2", "main": "src/mod.js", "license": "MIT", "author": "Tyfon", diff --git a/server/src/RagfairLinkedSlotItemService.ts b/server/src/RagfairLinkedSlotItemService.ts index 7f083e6..c53a5cd 100644 --- a/server/src/RagfairLinkedSlotItemService.ts +++ b/server/src/RagfairLinkedSlotItemService.ts @@ -20,7 +20,21 @@ export class RagfairLinkedSlotItemService extends RagfairLinkedItemService { if (slotName) { this.logger.info(`UIFixes: Finding items for specific slot ${tpl}:${slotName}`); - return this.getSpecificFilter(this.databaseService.getItems()[tpl], slotName); + + const resultSet = this.getSpecificFilter(this.databaseService.getItems()[tpl], slotName); + + // Default Inventory, for equipment slots + if (tpl === "55d7217a4bdc2d86028b456d") { + const categories = [...resultSet]; + const items = Object.keys(this.databaseService.getItems()).filter(tpl => + this.itemHelper.isOfBaseclasses(tpl, categories) + ); + + // Send the categories along too, some of them might actually be items + return new Set(items.concat(categories)); + } + + return resultSet; } return super.getLinkedItems(tpl); @@ -42,4 +56,6 @@ export class RagfairLinkedSlotItemService extends RagfairLinkedItemService { return results; } + + private getCategoryItems(category: string) {} }