using Aki.Reflection.Patching; using EFT.Hideout; using EFT.UI; using EFT.UI.Chat; using EFT.UI.Ragfair; using EFT.UI.Utilities.LightScroller; using HarmonyLib; using System; using System.Collections.Generic; using System.Reflection; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI; namespace UIFixes { public static class ScrollPatches { public static void Enable() { new EnhanceStashScrollingPatch().Enable(); new EnchanceTraderStashScrollingPatch().Enable(); new EnhanceFleaScrollingPatch().Enable(); new EnhanceMailScrollingPatch().Enable(); new MouseScrollingSpeedPatch().Enable(); new EnhanceHideoutScrollingPatch().Enable(); } private static bool HandleInput(ScrollRect scrollRect) { if (scrollRect != null) { if (Settings.UseHomeEnd.Value) { if (Input.GetKeyDown(KeyCode.Home)) { scrollRect.verticalNormalizedPosition = 1f; return true; } if (Input.GetKeyDown(KeyCode.End)) { scrollRect.verticalNormalizedPosition = 0f; return true; } } if (Settings.RebindPageUpDown.Value) { if (Input.GetKeyDown(KeyCode.PageUp)) { // Duplicate this code to avoid running it every frame Rect contentRect = scrollRect.content.rect; Rect viewRect = scrollRect.RectTransform().rect; float pageSize = viewRect.height / contentRect.height; scrollRect.verticalNormalizedPosition = Math.Min(1f, scrollRect.verticalNormalizedPosition + pageSize); return true; } if (Input.GetKeyDown(KeyCode.PageDown)) { // Duplicate this code to avoid running it every frame Rect contentRect = scrollRect.content.rect; Rect viewRect = scrollRect.RectTransform().rect; float pageSize = viewRect.height / contentRect.height; scrollRect.verticalNormalizedPosition = Math.Max(0f, scrollRect.verticalNormalizedPosition - pageSize); return true; } } } return false; } // LightScrollers don't expose heights that I can see, so just fudge it with fake OnScroll events private static bool HandleInput(LightScroller lightScroller) { if (lightScroller != null) { if (Settings.UseHomeEnd.Value) { if (Input.GetKeyDown(KeyCode.Home)) { lightScroller.SetScrollPosition(0f); return true; } if (Input.GetKeyDown(KeyCode.End)) { lightScroller.SetScrollPosition(1f); return true; } } if (Settings.RebindPageUpDown.Value) { if (Input.GetKeyDown(KeyCode.PageUp)) { var eventData = new PointerEventData(EventSystem.current) { scrollDelta = new Vector2(0f, 25f) }; lightScroller.OnScroll(eventData); return true; } if (Input.GetKeyDown(KeyCode.PageDown)) { var eventData = new PointerEventData(EventSystem.current) { scrollDelta = new Vector2(0f, -25f) }; lightScroller.OnScroll(eventData); return true; } } } return false; } private static IEnumerable RemovePageUpDownHandling(IEnumerable instructions) { foreach (var instruction in instructions) { if (instruction.LoadsConstant((int)KeyCode.PageUp)) { yield return new CodeInstruction(instruction) { operand = 0 }; } else if (instruction.LoadsConstant((int)KeyCode.PageDown)) { yield return new CodeInstruction(instruction) { operand = 0 }; } else { yield return instruction; } } } public class KeyScroller : MonoBehaviour { private ScrollRect scrollRect; public UnityEvent OnKeyScroll; public void Awake() { scrollRect = GetComponent(); OnKeyScroll = new(); } public void Update() { if (HandleInput(scrollRect)) { OnKeyScroll.Invoke(); } } } public class EnhanceStashScrollingPatch : ModulePatch { protected override MethodBase GetTargetMethod() { return AccessTools.Method(typeof(SimpleStashPanel), nameof(SimpleStashPanel.Update)); } [PatchPrefix] public static void Prefix(SimpleStashPanel __instance, ScrollRect ____stashScroll) { // For some reason, sometimes SimpleStashPanel doesn't have a reference to its own ScrollRect? HandleInput(____stashScroll ?? __instance.GetComponentInChildren()); } [PatchTranspiler] public static IEnumerable Transpile(IEnumerable instructions) { if (Settings.RebindPageUpDown.Value) { return RemovePageUpDownHandling(instructions); } return instructions; } } public class EnchanceTraderStashScrollingPatch : ModulePatch { protected override MethodBase GetTargetMethod() { return AccessTools.Method(typeof(TraderDealScreen), nameof(TraderDealScreen.Update)); } [PatchPrefix] public static void Prefix(TraderDealScreen.ETraderMode ___etraderMode_0, ScrollRect ____traderScroll, ScrollRect ____stashScroll) { HandleInput(___etraderMode_0 == TraderDealScreen.ETraderMode.Purchase ? ____traderScroll : ____stashScroll); } [PatchTranspiler] public static IEnumerable Transpile(IEnumerable instructions) { if (Settings.RebindPageUpDown.Value) { return RemovePageUpDownHandling(instructions); } return instructions; } } public class EnhanceFleaScrollingPatch : ModulePatch { protected override MethodBase GetTargetMethod() { return AccessTools.Method(typeof(OfferViewList), nameof(OfferViewList.Update)); } [PatchPrefix] public static void Prefix(LightScroller ____scroller) { HandleInput(____scroller); } [PatchTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { if (Settings.RebindPageUpDown.Value) { return RemovePageUpDownHandling(instructions); } return instructions; } } public class EnhanceHideoutScrollingPatch : ModulePatch { protected override MethodBase GetTargetMethod() { return AccessTools.Method(typeof(AreaScreenSubstrate), nameof(AreaScreenSubstrate.Awake)); } [PatchPostfix] public static void Postfix(AreaScreenSubstrate __instance) { ScrollRect scrollRect = __instance.transform.Find("Content/CurrentLevel/CurrentContainer/Scrollview")?.GetComponent(); if (scrollRect == null) { return; } scrollRect.GetOrAddComponent(); } } public class EnhanceMailScrollingPatch : ModulePatch { protected override MethodBase GetTargetMethod() { return AccessTools.Method(typeof(MessagesContainer), nameof(MessagesContainer.Update)); } [PatchPrefix] public static void Prefix(LightScroller ____scroller) { HandleInput(____scroller); } [PatchTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { if (Settings.RebindPageUpDown.Value) { return RemovePageUpDownHandling(instructions); } return instructions; } } public class MouseScrollingSpeedPatch : ModulePatch { protected override MethodBase GetTargetMethod() { return AccessTools.Method(typeof(ScrollRectNoDrag), nameof(ScrollRectNoDrag.OnScroll)); } [PatchPrefix] public static void Prefix(PointerEventData data) { int multi = Settings.UseRaidMouseScrollMulti.Value && Plugin.InRaid() ? Settings.MouseScrollMultiInRaid.Value : Settings.MouseScrollMulti.Value; data.scrollDelta *= multi; } } } }