Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TerminalScrollPatch v1.0.0
TerminalScrollPatch.dll
Decompiled a day agousing System; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("TerminalRelativeScroll")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("TerminalRelativeScroll")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("19e0a1ba-5c2c-4d94-99f0-91c651f9621e")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace TerminalRelativeScroll; [BepInPlugin("brabru.TerminalScrollPatch", "Terminal Scroll Patch", "1.0.0")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { internal static Plugin Instance; internal static PluginSettings Settings; internal static ManualLogSource StaticLogger; private void Awake() { Instance = this; StaticLogger = ((BaseUnityPlugin)this).Logger; Settings = new PluginSettings(((BaseUnityPlugin)this).Config); StaticLogger.LogInfo((object)$"Config: CustomScroll={Settings.RelativeScrollEnabled.Value}, LinesToScroll={Settings.LinesToScroll.Value}"); Harmony.CreateAndPatchAll(typeof(TerminalScrollPatch), (string)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"TerminalScrollPatch mod loaded (v81)"); } } public class PluginSettings { public ConfigEntry<bool> RelativeScrollEnabled { get; } public ConfigEntry<int> LinesToScroll { get; } public PluginSettings(ConfigFile config) { RelativeScrollEnabled = config.Bind<bool>("General", "CustomScrollEnabled", true, "If true, terminal scrolling is relative to line count. If false, vanilla behavior."); LinesToScroll = config.Bind<int>("General", "LinesToScroll", 8, "Number of lines to scroll when CustomScrollEnabled is true."); } } [HarmonyPatch] internal class TerminalScrollPatch { private static string cachedText; private static float scrollAmount; private static float originalScrollbarValue; private static float currentScrollDelta; private static bool shouldOverride; private static FieldInfo terminalField; private static bool terminalFieldFromStartOfRound; static TerminalScrollPatch() { cachedText = ""; scrollAmount = 1f / 3f; terminalField = AccessTools.GetDeclaredFields(typeof(PlayerControllerB)).FirstOrDefault((FieldInfo f) => f.FieldType == typeof(Terminal)); if (terminalField == null) { terminalField = AccessTools.GetDeclaredFields(typeof(StartOfRound)).FirstOrDefault((FieldInfo f) => f.FieldType == typeof(Terminal)); terminalFieldFromStartOfRound = true; } else { terminalFieldFromStartOfRound = false; } if (terminalField != null) { Plugin.StaticLogger.LogInfo((object)("TerminalScrollPatch: found Terminal field '" + terminalField.Name + "' in " + terminalField.DeclaringType.Name)); } else { Plugin.StaticLogger.LogWarning((object)"TerminalScrollPatch: no Terminal field found! Will fallback to FindObjectOfType."); } } [HarmonyTargetMethod] public static MethodBase TargetMethod() { string[] obj = new string[3] { "ScrollMouse_performed", "UpdateTerminalMouseScroll", "TerminalScroll_performed" }; Type typeFromHandle = typeof(PlayerControllerB); string[] array = obj; foreach (string text in array) { MethodInfo methodInfo = AccessTools.Method(typeFromHandle, text, new Type[1] { typeof(CallbackContext) }, (Type[])null); if (methodInfo != null) { Plugin.StaticLogger.LogInfo((object)("TerminalScrollPatch: method found -> " + methodInfo.DeclaringType?.Name + "." + methodInfo.Name)); return methodInfo; } } Plugin.StaticLogger.LogError((object)"TerminalScrollPatch: no terminal scroll method found! Mod will not work."); return null; } [HarmonyPrefix] private static void Prefix(PlayerControllerB __instance, CallbackContext context) { Plugin.StaticLogger.LogDebug((object)"Prefix: Entered"); currentScrollDelta = ((CallbackContext)(ref context)).ReadValue<float>(); Plugin.StaticLogger.LogDebug((object)$"Prefix: scrollDelta = {currentScrollDelta}"); if (Mathf.Approximately(currentScrollDelta, 0f)) { shouldOverride = false; Plugin.StaticLogger.LogDebug((object)"Prefix: scrollDelta zero, setting shouldOverride=false"); return; } if ((Object)(object)__instance.terminalScrollVertical != (Object)null) { originalScrollbarValue = __instance.terminalScrollVertical.value; Plugin.StaticLogger.LogDebug((object)$"Prefix: originalScrollbarValue = {originalScrollbarValue}"); } else { Plugin.StaticLogger.LogWarning((object)"Prefix: terminalScrollVertical is null!"); } Terminal terminal = GetTerminal(__instance); bool inTerminalMenu = __instance.inTerminalMenu; bool flag = Plugin.Settings != null; bool flag2 = flag && Plugin.Settings.RelativeScrollEnabled.Value; bool flag3 = (Object)(object)terminal != (Object)null; Plugin.StaticLogger.LogDebug((object)$"Prefix: inTerminalMenu={inTerminalMenu}, settingsExist={flag}, relativeEnabled={flag2}, terminalExists={flag3}"); shouldOverride = inTerminalMenu && flag && flag2 && flag3; Plugin.StaticLogger.LogDebug((object)$"Prefix: shouldOverride = {shouldOverride}"); } [HarmonyPostfix] private static void Postfix(PlayerControllerB __instance) { Plugin.StaticLogger.LogDebug((object)"Postfix: Entered"); if (!shouldOverride) { Plugin.StaticLogger.LogDebug((object)"Postfix: shouldOverride false, exiting"); return; } Scrollbar terminalScrollVertical = __instance.terminalScrollVertical; if ((Object)(object)terminalScrollVertical == (Object)null) { Plugin.StaticLogger.LogWarning((object)"Postfix: scrollbar is null"); return; } Terminal terminal = GetTerminal(__instance); if ((Object)(object)terminal == (Object)null) { Plugin.StaticLogger.LogWarning((object)"Postfix: terminal is null"); return; } float num = Mathf.Sign(currentScrollDelta); Plugin.StaticLogger.LogDebug((object)$"Postfix: direction = {num}"); string currentText = terminal.currentText; if (string.CompareOrdinal(currentText, cachedText) != 0) { cachedText = currentText; int num2 = cachedText.Count((char c) => c == '\n') + 1; scrollAmount = (float)Plugin.Settings.LinesToScroll.Value / (float)num2; Plugin.StaticLogger.LogInfo((object)$"Recalculated scroll: lines={num2}, scrollAmount={scrollAmount:F4}"); } float num3 = originalScrollbarValue + num * scrollAmount; num3 = Mathf.Clamp01(num3); Plugin.StaticLogger.LogInfo((object)$"Postfix: original={originalScrollbarValue}, desired={num3}, delta={num * scrollAmount}"); terminalScrollVertical.value = num3; } private static Terminal GetTerminal(PlayerControllerB player) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown if (terminalField != null) { if (!terminalFieldFromStartOfRound) { return (Terminal)terminalField.GetValue(player); } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null) { return (Terminal)terminalField.GetValue(instance); } } return Object.FindObjectOfType<Terminal>(); } }