using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.Json; using System.Text.RegularExpressions; using AIGraph; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using BetterTerminal.TerminalItems; using GameData; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem.Collections.Generic; using LevelGeneration; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("STFO")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("BetterTerminal")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+2642f2721028b39a90b2dee3ed12b0c02c2e1d56")] [assembly: AssemblyProduct("BetterTerminal")] [assembly: AssemblyTitle("BetterTerminal")] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace BetterTerminal { [BepInPlugin("BetterTerminal", "BetterTerminal", "1.1.3")] public class Plugin : BasePlugin { [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "TryUpdateLineForAutoComplete")] internal static class AutoCompletePatch { private static LG_ComputerTerminalCommandInterpreter? _selectionInterpreter; private static readonly List SelectionCandidates = new List(); private static readonly List RenderedSelectionLines = new List(); private static string _selectionPrefix = string.Empty; private static string _selectionLine = string.Empty; private static int _selectionIndex; private static int _selectionScreenLineCount; private static void Postfix(LG_ComputerTerminalCommandInterpreter __instance, string input, ref string autoCompletedLine, ref bool __result) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown ManualLogSource modLog = ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(46, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] INPUT='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(input); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' NATIVE_RESULT="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(__result); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" NATIVE_OUTPUT='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(autoCompletedLine); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog.LogDebug(val); if (!EnableFuzzySearch.Value || string.IsNullOrWhiteSpace(input)) { ModLog.LogDebug((object)"[TAB] FUZZY DISABLED OR EMPTY INPUT"); return; } string text = input.TrimEnd().ToUpperInvariant(); int num = text.LastIndexOf('|'); int i; for (i = num + 1; i < text.Length && text[i] == ' '; i++) { } string text2 = text.Substring(0, i); string text3 = text.Substring(i); if (text3.Length == 0) { return; } int num2 = text3.IndexOf(' '); if (num2 < 0) { if (__result || !EnableCommandFuzzySearch.Value) { ModLog.LogDebug((object)"[TAB] KEEPING NATIVE COMMAND AUTOCOMPLETE"); } else { CompleteCommand(__instance, text3, text2, num >= 0, ref autoCompletedLine, ref __result); } } else if (!EnableIdentifierFuzzySearch.Value) { ModLog.LogDebug((object)"[TAB] IDENTIFIER FUZZY DISABLED"); } else { CompleteArgument(__instance, text3, num2, text2, ref autoCompletedLine, ref __result); } } private static void CompleteArgument(LG_ComputerTerminalCommandInterpreter interpreter, string input, int firstSpace, string segmentPrefix, ref string output, ref bool result) { if (!Enum.TryParse(input.Substring(0, firstSpace), ignoreCase: true, out var result2)) { return; } if (((uint)(result2 - 1) <= 2u || (uint)(result2 - 5) <= 1u) ? true : false) { CompleteIdentifier(interpreter, input, firstSpace, segmentPrefix, ref output, ref result); return; } string[] array = input.Split(' ', StringSplitOptions.RemoveEmptyEntries); IEnumerable enumerable = null; bool flag = (uint)(result2 - 11) <= 1u; if (flag && array.Length == 2) { enumerable = from name in Enum.GetNames() select name.ToUpperInvariant(); } else if (result2 == CommandType.Sort && array.Length == 3) { enumerable = new string[1] { "DESC" }; } else if (result2 == CommandType.Help && array.Length == 2) { enumerable = from name in Enum.GetNames() select name.ToUpperInvariant(); } else if (result2 == CommandType.BetterTerminal && array.Length == 2) { enumerable = from name in Enum.GetNames() select name.ToUpperInvariant(); } else if (result2 == CommandType.Docs && array.Length == 2) { enumerable = from name in Enum.GetNames() select name.ToUpperInvariant(); } else if (result2 == CommandType.History && array.Length == 2) { enumerable = from name in Enum.GetNames() select name.ToUpperInvariant(); } else if (result2 == CommandType.Config && array.Length == 2) { enumerable = ConfigCommandPatch.AutoCompleteKeys; } else if (result2 == CommandType.Config && array.Length == 3) { enumerable = ConfigCommandPatch.AutoCompleteValues(array[1]); } if (enumerable != null) { int num = input.LastIndexOf(' '); string input2 = input.Substring(num + 1); if (TryFindBestMatches(input2, enumerable, "ARGUMENT", out List matches)) { string prefix = BuildArgumentPrefix(segmentPrefix, input, num); ApplyMatches(interpreter, input2, prefix, matches, ref output, ref result); } } } private static void CompleteCommand(LG_ComputerTerminalCommandInterpreter interpreter, string input, string prefix, bool pipelineStage, ref string output, ref bool result) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (pipelineStage && EnablePipelines.Value) { PipelineStage[] values = Enum.GetValues(); for (int i = 0; i < values.Length; i++) { PipelineStage pipelineStage2 = values[i]; list.Add(pipelineStage2.ToString().ToUpperInvariant()); } } else { Enumerator enumerator = interpreter.m_commandsPerString.Keys.GetEnumerator(); while (enumerator.MoveNext()) { string current = enumerator.Current; if (!LG_ComputerTerminalCommandInterpreter.CommandIsAlwaysHidden(interpreter.m_commandsPerString[current])) { list.Add(current.ToUpperInvariant()); } } list.AddRange(ModCommands.Names); } if (!TryFindBestMatches(input, list, "COMMAND", out List matches)) { ModLog.LogDebug((object)"[TAB] NO COMMAND MATCHES"); } else { ApplyMatches(interpreter, input, prefix, matches, ref output, ref result); } } private static void CompleteIdentifier(LG_ComputerTerminalCommandInterpreter interpreter, string input, int firstSpace, string segmentPrefix, ref string output, ref bool result) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Expected O, but got Unknown string text = input.Substring(0, firstSpace); bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val; if (!Enum.TryParse(text, ignoreCase: true, out var result2)) { ManualLogSource modLog = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(46, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] UNKNOWN COMMAND '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(text); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' FOR IDENTIFIER SEARCH"); } modLog.LogDebug(val); return; } flag = (((uint)(result2 - 1) <= 2u || (uint)(result2 - 5) <= 1u) ? true : false); if (!flag) { ManualLogSource modLog2 = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(51, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] COMMAND '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(result2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' DOES NOT SUPPORT IDENTIFIER SEARCH"); } modLog2.LogDebug(val); return; } int num = input.LastIndexOf(' '); if (num == input.Length - 1) { return; } LG_LevelInteractionManager current = LG_LevelInteractionManager.Current; Dictionary val2 = ((current != null) ? current.m_terminalItemsByKeyString : null); if (val2 == null) { ModLog.LogDebug((object)"[TAB] TERMINAL ITEM DICTIONARY IS NULL"); return; } string text2 = input.Substring(num + 1); bool flag2 = text2.IndexOfAny(new char[2] { '_', '-' }) >= 0; HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); Enumerator enumerator = val2.Keys.GetEnumerator(); while (enumerator.MoveNext()) { string text3 = enumerator.Current.ToUpperInvariant(); if (flag2) { hashSet.Add(text3); continue; } string[] array = text3.Split(new char[2] { '_', '-' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item in array) { hashSet.Add(item); } } ManualLogSource modLog3 = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(34, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] CHECKING "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(hashSet.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" IDENTIFIERS FOR '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(text2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog3.LogDebug(val); if (!TryFindBestMatches(text2, hashSet, "IDENTIFIER", out List matches)) { ModLog.LogDebug((object)"[TAB] NO IDENTIFIER MATCHES"); return; } string prefix = BuildArgumentPrefix(segmentPrefix, input, num); ApplyMatches(interpreter, text2, prefix, matches, ref output, ref result); } private static string BuildArgumentPrefix(string segmentPrefix, string input, int activeWordSeparator) { string[] value = input.Substring(0, activeWordSeparator).Split(' ', StringSplitOptions.RemoveEmptyEntries); return segmentPrefix + string.Join(" ", value) + " "; } private static bool TryFindBestMatches(string input, IEnumerable candidates, string candidateType, out List matches) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Expected O, but got Unknown string text = input.ToUpperInvariant(); matches = new List(); List list = new List(); List<(string, int)> list2 = new List<(string, int)>(); bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val; foreach (string candidate in candidates) { if (string.IsNullOrWhiteSpace(candidate)) { continue; } string text2 = candidate.ToUpperInvariant(); if (text2.StartsWith(text, StringComparison.OrdinalIgnoreCase)) { list.Add(candidate); ManualLogSource modLog = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(40, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB:"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(candidateType); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ITEM='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(candidate); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' PREFIX=True ACCEPTED=True"); } modLog.LogDebug(val); continue; } int num = Levenshtein.Compute(text, text2); bool flag2 = num <= MaximumLevenshteinDistance.Value; ManualLogSource modLog2 = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(34, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB:"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(candidateType); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ITEM='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(candidate); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' DISTANCE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(num); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ACCEPTED="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(flag2); } modLog2.LogDebug(val); if (flag2) { list2.Add((candidate, num)); } } if (list.Count > 0) { list.Sort(StringComparer.OrdinalIgnoreCase); matches.AddRange(list); ManualLogSource modLog3 = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(31, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB:"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(candidateType); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] PREFIX_COUNT="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(matches.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" MATCHES=["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(string.Join(", ", matches)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]"); } modLog3.LogDebug(val); return true; } list2.Sort(delegate((string Candidate, int Distance) left, (string Candidate, int Distance) right) { int num2 = left.Distance.CompareTo(right.Distance); return (num2 == 0) ? StringComparer.OrdinalIgnoreCase.Compare(left.Candidate, right.Candidate) : num2; }); foreach (var item2 in list2) { string item = item2.Item1; matches.Add(item); } ManualLogSource modLog4 = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(33, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB:"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(candidateType); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ACCEPTED_COUNT="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(matches.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" MATCHES=["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(string.Join(", ", matches)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]"); } modLog4.LogDebug(val); return matches.Count > 0; } private static void ApplyMatches(LG_ComputerTerminalCommandInterpreter interpreter, string input, string prefix, List matches, ref string output, ref bool result) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val; if (matches.Count == 1) { ManualLogSource modLog = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(30, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] SINGLE MATCH SELECTED='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(matches[0]); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog.LogDebug(val); ClearSelection(); output = prefix + matches[0]; result = true; return; } if (AmbiguousMatches.Value == AmbiguousMatchMode.CommonPrefix) { ClearSelection(); string text = FindCommonPrefix(matches); ManualLogSource modLog2 = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(39, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] COMMON PREFIX='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(text); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' CANDIDATE_COUNT="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(matches.Count); } modLog2.LogDebug(val); if (text.Length > input.Length) { output = prefix + text; result = true; } return; } _selectionInterpreter = interpreter; _selectionPrefix = prefix; _selectionIndex = 0; SelectionCandidates.Clear(); SelectionCandidates.AddRange(matches); _selectionLine = prefix + SelectionCandidates[_selectionIndex]; ManualLogSource modLog3 = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(48, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] ARROW SELECTION STARTED COUNT="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(SelectionCandidates.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" SELECTED='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(_selectionLine); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog3.LogDebug(val); RenderSelectionList(); output = _selectionLine; result = true; } private static string BuildSelectionList(List candidates, int selectedIndex) { List list = new List { "FUZZY MATCHES - USE UP/DOWN ARROWS:" }; for (int i = 0; i < candidates.Count; i++) { string value = ((i == selectedIndex) ? "->" : " "); list.Add($"{value} {i + 1}. {candidates[i]}"); } return string.Join("\n", list); } private static string FindCommonPrefix(List candidates) { string text = candidates[0]; for (int i = 1; i < candidates.Count; i++) { if (text.Length <= 0) { break; } string text2 = candidates[i]; int num = Math.Min(text.Length, text2.Length); int j; for (j = 0; j < num && char.ToUpperInvariant(text[j]) == char.ToUpperInvariant(text2[j]); j++) { } text = text.Substring(0, j); } return text; } internal static bool TryStepSelection(LG_ComputerTerminalCommandInterpreter interpreter, bool stepPrevious, ref string result) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val; if (AmbiguousMatches.Value != AmbiguousMatchMode.ArrowSelection || SelectionCandidates.Count < 2) { ManualLogSource modLog = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(39, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ARROW] SELECTION INACTIVE MODE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(AmbiguousMatches.Value); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" COUNT="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(SelectionCandidates.Count); } modLog.LogDebug(val); return false; } int num = ((!stepPrevious) ? 1 : (-1)); _selectionIndex = (_selectionIndex + num + SelectionCandidates.Count) % SelectionCandidates.Count; _selectionLine = _selectionPrefix + SelectionCandidates[_selectionIndex]; ManualLogSource modLog2 = ModLog; val = new BepInExDebugLogInterpolatedStringHandler(37, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ARROW] DIRECTION="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(stepPrevious ? "UP" : "DOWN"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" INDEX="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(_selectionIndex); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" SELECTED='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(_selectionLine); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog2.LogDebug(val); RenderSelectionList(); result = _selectionLine; return true; } private static void RenderSelectionList() { RemoveSelectionList(); if (_selectionInterpreter != null && SelectionCandidates.Count >= 2) { string[] array = BuildSelectionList(SelectionCandidates, _selectionIndex).Split('\n'); string[] array2 = array; foreach (string text in array2) { _selectionInterpreter.m_screenBuffer.Add(text); RenderedSelectionLines.Add(text); } _selectionScreenLineCount = array.Length; } } private static void RemoveSelectionList() { if (_selectionInterpreter == null || _selectionScreenLineCount == 0) { return; } for (int num = RenderedSelectionLines.Count - 1; num >= 0; num--) { int num2 = _selectionInterpreter.m_screenBuffer.Count - 1; if (num2 < 0 || !string.Equals(_selectionInterpreter.m_screenBuffer[num2], RenderedSelectionLines[num], StringComparison.Ordinal)) { ModLog.LogDebug((object)"[SELECTION] SCREEN BUFFER CHANGED; SKIPPING UNSAFE LINE REMOVAL"); break; } _selectionInterpreter.m_screenBuffer.RemoveAt(num2); } RenderedSelectionLines.Clear(); _selectionScreenLineCount = 0; } internal static void ClearSelection() { RemoveSelectionList(); _selectionInterpreter = null; _selectionPrefix = string.Empty; _selectionLine = string.Empty; _selectionIndex = 0; _selectionScreenLineCount = 0; SelectionCandidates.Clear(); RenderedSelectionLines.Clear(); } } [HarmonyPatch(typeof(LG_ComputerTerminal), "Update")] internal static class TerminalUpdatePatch { private static bool Prefix(LG_ComputerTerminal __instance) { if (!EnableHistorySearch.Value || TerminalInputReservationRegistry.IsReserved(__instance.SyncID)) { return true; } if (HistorySearchManager.IsActive(__instance.SyncID)) { return !HistorySearchManager.HandleUpdate(__instance); } if (InputMapper.GetButtonDown.Invoke((InputAction)15, (eFocusState)8) && HistorySearchManager.TryOpen(__instance)) { return false; } return true; } private static void Postfix(LG_ComputerTerminal __instance) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown if (HistorySearchManager.IsActive(__instance.SyncID) || TerminalInputReservationRegistry.IsReserved(__instance.SyncID)) { return; } bool flag = InputMapper.GetButtonDown.Invoke((InputAction)15, (eFocusState)8); bool flag2 = InputMapper.GetButtonDown.Invoke((InputAction)16, (eFocusState)8); if (flag || flag2) { ManualLogSource modLog = ModLog; bool flag3 = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(33, 3, ref flag3); if (flag3) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ARROW INPUT] UP="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(flag); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" DOWN="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(flag2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" TERMINAL="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(__instance.SyncID); } modLog.LogDebug(val); string result = string.Empty; if (AutoCompletePatch.TryStepSelection(__instance.m_command, flag, ref result)) { __instance.m_currentLine = result; __instance.m_command.m_inputBufferStep = 0; } } } } internal const string PluginVersion = "1.1.3"; private Harmony? _harmony; internal static ConfigFile Settings { get; private set; } internal static ManualLogSource ModLog { get; private set; } internal static ConfigEntry EnableFuzzySearch { get; private set; } internal static ConfigEntry EnableCommandFuzzySearch { get; private set; } internal static ConfigEntry EnableIdentifierFuzzySearch { get; private set; } internal static ConfigEntry AmbiguousMatches { get; private set; } internal static ConfigEntry MaximumLevenshteinDistance { get; private set; } internal static ConfigEntry LogConsumablePickups { get; private set; } internal static ConfigEntry EnableConsumableTerminalItems { get; private set; } internal static ConfigEntry ShowConsumablesInNativeList { get; private set; } internal static ConfigEntry EnableGlowStickTerminalItems { get; private set; } internal static ConfigEntry EnableCFoamGrenadeTerminalItems { get; private set; } internal static ConfigEntry EnableCFoamMineTerminalItems { get; private set; } internal static ConfigEntry EnableExplosiveMineTerminalItems { get; private set; } internal static ConfigEntry EnableFogRepellerTerminalItems { get; private set; } internal static ConfigEntry EnableLockMelterTerminalItems { get; private set; } internal static ConfigEntry EnableLongRangeFlashlightTerminalItems { get; private set; } internal static ConfigEntry EnableHealthSyringeTerminalItems { get; private set; } internal static ConfigEntry EnableBoostSyringeTerminalItems { get; private set; } internal static ConfigEntry EnablePipelines { get; private set; } internal static ConfigEntry EnableHistorySearch { get; private set; } internal static ConfigEntry MaximumHistoryEntries { get; private set; } internal static ConfigEntry MaximumVisibleHistoryResults { get; private set; } internal static ConfigEntry HistoryPersistence { get; private set; } internal static ConfigEntry Language { get; private set; } internal static ConfigEntry ShowNeofetchOnTerminalStart { get; private set; } internal static ConfigEntry NeofetchDisplayMode { get; private set; } internal static ConfigEntry EnableIdleScreenImage { get; private set; } internal static ConfigEntry IdleScreenColors { get; private set; } internal static ConfigEntry ImageIntensityPercent { get; private set; } internal static ConfigEntry ImageOpacityPercent { get; private set; } internal static ConfigEntry ImageRotationDegrees { get; private set; } internal static ConfigEntry ImageFlipHorizontal { get; private set; } internal static ConfigEntry ImageFlipVertical { get; private set; } internal static ConfigEntry EnableTerminalBackground { get; private set; } internal static ConfigEntry TerminalTextColor { get; private set; } internal static ConfigEntry TerminalTextIntensityPercent { get; private set; } public override void Load() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Settings = ((BasePlugin)this).Config; ModLog = ((BasePlugin)this).Log; BindConfiguration(); LocalizationService.Initialize(); HistoryStore.Initialize(); NeofetchService.Initialize(); IdleScreenService.Initialize(); _harmony = new Harmony("BetterTerminal"); _harmony.PatchAll(); ((BasePlugin)this).Log.LogInfo((object)"BetterTerminal loaded"); } private void BindConfiguration() { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Expected O, but got Unknown //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Expected O, but got Unknown //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Expected O, but got Unknown //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Expected O, but got Unknown //IL_04d1: Unknown result type (might be due to invalid IL or missing references) //IL_04db: Expected O, but got Unknown Language = ((BasePlugin)this).Config.Bind("Localization", "Language", "en", "JSON language filename without extension. Example: en, es."); EnableFuzzySearch = ((BasePlugin)this).Config.Bind("Fuzzy Search", "Enabled", true, "Enables or disables all terminal fuzzy search features."); EnableCommandFuzzySearch = ((BasePlugin)this).Config.Bind("Fuzzy Search", "Commands", true, "Allows autocomplete to correct command names."); EnableIdentifierFuzzySearch = ((BasePlugin)this).Config.Bind("Fuzzy Search", "Identifiers", true, "Allows autocomplete to correct active identifier words used by LIST, QUERY, PING, MARK, and UNMARK."); AmbiguousMatches = ((BasePlugin)this).Config.Bind("Fuzzy Search", "AmbiguousMatches", AmbiguousMatchMode.CommonPrefix, "CommonPrefix completes the shared prefix. ArrowSelection lets the user choose with arrow keys."); MaximumLevenshteinDistance = ((BasePlugin)this).Config.Bind("Fuzzy Search", "MaximumLevenshteinDistance", 2, new ConfigDescription("Maximum fuzzy-search distance. Higher values produce less precise matches.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 10), Array.Empty())); LogConsumablePickups = ((BasePlugin)this).Config.Bind("Terminal Items", "DiagnosticLogging", false, "Logs uncollected consumable data for diagnostics and type identification."); EnableConsumableTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "Enabled", true, "Enables LIST, QUERY, and PING for uncollected consumables."); ShowConsumablesInNativeList = ((BasePlugin)this).Config.Bind("Terminal Items", "ShowInNativeList", false, "Includes registered consumables in broad native LIST searches such as LIST U. LIST CONSUMABLES and pipelines remain available when disabled."); EnableGlowStickTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "GlowSticks", true, "Registers uncollected glow sticks with terminals."); EnableCFoamGrenadeTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "CFoamGrenades", true, "Registers uncollected C-Foam grenades with terminals."); EnableCFoamMineTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "CFoamMines", true, "Registers uncollected C-Foam tripmines with terminals."); EnableExplosiveMineTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "Mines", true, "Registers uncollected explosive tripmines with terminals."); EnableFogRepellerTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "FogRepellers", true, "Registers uncollected fog repellers with terminals."); EnableLockMelterTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "LockMelters", true, "Registers uncollected lock melters with terminals."); EnableLongRangeFlashlightTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "LongRangeFlashlights", true, "Registers uncollected long-range flashlights with terminals."); EnableHealthSyringeTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "I2LPSyringes", true, "Registers uncollected I2-LP syringes with terminals."); EnableBoostSyringeTerminalItems = ((BasePlugin)this).Config.Bind("Terminal Items", "IIxSyringes", true, "Registers uncollected IIx syringes with terminals."); EnablePipelines = ((BasePlugin)this).Config.Bind("Pipelines", "Enabled", true, "Enables typed command pipelines."); EnableHistorySearch = ((BasePlugin)this).Config.Bind("History", "Enabled", true, "Opens interactive history search when Up is pressed on an empty line."); MaximumHistoryEntries = ((BasePlugin)this).Config.Bind("History", "MaximumEntries", 500, new ConfigDescription("Maximum commands retained during the session.", (AcceptableValueBase)(object)new AcceptableValueRange(10, 5000), Array.Empty())); MaximumVisibleHistoryResults = ((BasePlugin)this).Config.Bind("History", "MaximumVisibleResults", 15, new ConfigDescription("Maximum visible results in history search.", (AcceptableValueBase)(object)new AcceptableValueRange(3, 50), Array.Empty())); HistoryPersistence = ((BasePlugin)this).Config.Bind("History", "Persistence", HistoryPersistenceMode.Session, "Session keeps commands only until GTFO closes. Disk restores history between sessions."); ShowNeofetchOnTerminalStart = ((BasePlugin)this).Config.Bind("Neofetch", "ShowOnTerminalStart", true, "Shows neofetch when terminal interaction begins."); NeofetchDisplayMode = ((BasePlugin)this).Config.Bind("Neofetch", "Mode", NeofetchMode.Normal, "Normal uses bundled artwork. Custom reads BepInEx/config/BetterTerminal/neofetch.txt."); EnableIdleScreenImage = ((BasePlugin)this).Config.Bind("Idle Screen", "Enabled", true, "Shows idle-screen.png on the login display while the terminal is not in use."); IdleScreenColors = ((BasePlugin)this).Config.Bind("Idle Screen", "ColorMode", IdleScreenColorMode.Image, "Image preserves PNG RGB colors. Terminal applies the original GTFO display tint."); ImageIntensityPercent = ((BasePlugin)this).Config.Bind("Terminal Appearance", "ImageIntensityPercent", 35, new ConfigDescription("Image RGB intensity.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100), Array.Empty())); ImageOpacityPercent = ((BasePlugin)this).Config.Bind("Terminal Appearance", "ImageOpacityPercent", 25, new ConfigDescription("Interactive background opacity.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ImageRotationDegrees = ((BasePlugin)this).Config.Bind("Terminal Appearance", "ImageRotationDegrees", 0, "Additional rotation: 0, 90, 180, or 270 degrees."); ImageFlipHorizontal = ((BasePlugin)this).Config.Bind("Terminal Appearance", "FlipHorizontal", false, "Flips the image horizontally after correcting GTFO display UVs."); ImageFlipVertical = ((BasePlugin)this).Config.Bind("Terminal Appearance", "FlipVertical", false, "Flips the image vertically after correcting GTFO display UVs."); EnableTerminalBackground = ((BasePlugin)this).Config.Bind("Terminal Appearance", "InteractiveBackground", false, "Shows idle-screen.png as a background during terminal interaction."); TerminalTextColor = ((BasePlugin)this).Config.Bind("Terminal Appearance", "TextColor", "DEFAULT", "Terminal text color as RGB/RGBA hex, for example #80FFD0. DEFAULT preserves GTFO colors."); TerminalTextIntensityPercent = ((BasePlugin)this).Config.Bind("Terminal Appearance", "TextIntensityPercent", 100, new ConfigDescription("Custom text RGB intensity. Lower values reduce bloom without changing hue.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100), Array.Empty())); } } public enum CommandType { Unknown, Ping, Query, List, Config, Mark, Unmark, Commands, Help, Neofetch, IdleScreen, Where, Sort, Take, Count, Run, Stfo, BetterTerminal, Docs, History } public enum AmbiguousMatchMode { CommonPrefix, ArrowSelection } public enum HelpTopic { BetterTerminal, Search, History, Pipelines, Markers, Consumables, Appearance, Config, Stfo, Docs } public enum BetterTerminalAction { Status } public enum DocsAction { Open } public enum ConfigProfile { Vanilla, Convenient, Full } public enum HistoryPersistenceMode { Session, Disk } public enum HistoryAction { Clear } public enum TerminalItemCategory { All, Consumable, Native } public static class CommandTypeExtensions { public static string Token(this CommandType command) { return command.ToString().ToUpperInvariant(); } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class CommandsListPatch { private static void Postfix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { CommandType result; bool flag = !Enum.TryParse(inputString.Trim().ToUpperInvariant(), ignoreCase: true, out result); if (!flag) { bool flag2 = (uint)(result - 7) <= 1u; flag = !flag2; } if (!flag) { string[] array = ModCommands.BuildCommandsSection().Split('\n'); foreach (string text in array) { __instance.m_screenBuffer.Add(text); } __instance.ResetLinesSinceCommand(); } } internal static IReadOnlyList BuildLines(LG_ComputerTerminalCommandInterpreter interpreter, CommandType commandType) { List list = new List(); if (commandType == CommandType.Help) { list.Add(LocalizationService.Text("help.intro")); list.Add(LocalizationService.Text("help.navigation")); list.Add(string.Empty); } list.Add(LocalizationService.Text("commands.available")); list.Add(string.Empty); list.AddRange(BuildNativeCommands(interpreter)); list.AddRange(ModCommands.BuildCommandsSection().Split('\n')); return list; } private static IEnumerable BuildNativeCommands(LG_ComputerTerminalCommandInterpreter interpreter) { SortedSet sortedSet = new SortedSet(StringComparer.OrdinalIgnoreCase); Enumerator enumerator = interpreter.m_commandsPerString.Keys.GetEnumerator(); while (enumerator.MoveNext()) { string current = enumerator.Current; sortedSet.Add(current.ToUpperInvariant()); } foreach (string item in sortedSet) { yield return item; } } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class ConfigCommandPatch { internal static readonly string[] AutoCompleteKeys = new string[39] { "RELOAD", "SEARCH", "HISTORY", "ITEMS", "APPEARANCE", "PROFILE", "RESET", "ENABLED", "COMMANDS", "IDENTIFIERS", "GLOWSTICKS", "CFOAMGRENADES", "CFOAMMINES", "MINES", "FOGREPELLERS", "LOCKMELTERS", "FLASHLIGHTS", "I2LPSYRINGES", "IIXSYRINGES", "CONSUMABLESINLIST", "PIPELINES", "HISTORYLIMIT", "HISTORYVISIBLE", "HISTORYMODE", "LANGUAGE", "NEOFETCH", "NEOFETCHMODE", "IDLESCREEN", "IDLECOLORS", "BACKGROUND", "IMAGEINTENSITY", "IMAGEOPACITY", "IMAGEROTATION", "IMAGEFLIPH", "IMAGEFLIPV", "TEXTCOLOR", "TEXTINTENSITY", "DISTANCE", "MODE" }; internal static IEnumerable? AutoCompleteValues(string key) { switch (key) { case "PROFILE": return from name in Enum.GetNames() select name.ToUpperInvariant(); case "RESET": return new string[2] { "ALL", "APPEARANCE" }; case "NEOFETCHMODE": return from name in Enum.GetNames() select name.ToUpperInvariant(); case "IDLECOLORS": return from name in Enum.GetNames() select name.ToUpperInvariant(); case "MODE": return from name in Enum.GetNames() select name.ToUpperInvariant(); case "HISTORYMODE": return from name in Enum.GetNames() select name.ToUpperInvariant(); case "IMAGEROTATION": return new string[4] { "0", "90", "180", "270" }; case "TEXTCOLOR": return new string[1] { "DEFAULT" }; case "LANGUAGE": return new string[2] { "EN", "ES" }; case "ENABLED": case "HISTORY": case "ITEMS": case "MINES": case "FOGREPELLERS": case "I2LPSYRINGES": case "BACKGROUND": case "GLOWSTICKS": case "IDLESCREEN": case "IMAGEFLIPH": case "IMAGEFLIPV": case "CFOAMMINES": case "IDENTIFIERS": case "LOCKMELTERS": case "FLASHLIGHTS": case "IIXSYRINGES": case "CFOAMGRENADES": case "PIPELINES": case "COMMANDS": case "NEOFETCH": case "CONSUMABLESINLIST": return new string[2] { "ON", "OFF" }; default: return null; } } private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { string text = inputString.Trim().ToUpperInvariant(); string[] array = text.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0 || !Enum.TryParse(array[0], ignoreCase: true, out var result) || result != CommandType.Config) { return true; } Plugin.AutoCompletePatch.ClearSelection(); WriteImmediate(__instance, text, Execute(array)); return false; } private static void WriteImmediate(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string response) { TerminalCommandOutput.WriteImmediate(interpreter, commandLine, response.Split('\n')); } private static string Execute(string[] arguments) { if (arguments.Length == 1) { return CurrentConfiguration(); } if (arguments.Length == 2 && arguments[1] == "RELOAD") { Plugin.Settings.Reload(); HistoryStore.ReloadForPersistenceChange(); LocalizationService.Reload(); NeofetchService.Reload(); IdleScreenService.Reload(); TerminalAppearanceService.RefreshAll(); ConsumableTerminalRegistry.RefreshAll(); return LocalizationService.Text("config.reloaded") + "\n" + CurrentConfiguration(); } bool flag = arguments.Length == 2; if (flag) { bool flag2; switch (arguments[1]) { case "SEARCH": case "HISTORY": case "ITEMS": case "APPEARANCE": flag2 = true; break; default: flag2 = false; break; } flag = flag2; } if (flag) { return Section(arguments[1]); } if (arguments.Length == 2 && arguments[1] == "RESET") { return ResetConfiguration("ALL"); } if (arguments.Length == 3 && arguments[1] == "RESET") { return ResetConfiguration(arguments[2]); } if (arguments.Length == 3 && arguments[1] == "PROFILE") { return ApplyProfile(arguments[2]); } if (arguments.Length != 3) { return Help(); } return arguments[1] switch { "ENABLED" => SetBoolean(Plugin.EnableFuzzySearch, arguments[2], "ENABLED"), "COMMANDS" => SetBoolean(Plugin.EnableCommandFuzzySearch, arguments[2], "COMMANDS"), "IDENTIFIERS" => SetBoolean(Plugin.EnableIdentifierFuzzySearch, arguments[2], "IDENTIFIERS"), "ITEMS" => SetTerminalItemBoolean(Plugin.EnableConsumableTerminalItems, arguments[2], "ITEMS"), "GLOWSTICKS" => SetTerminalItemBoolean(Plugin.EnableGlowStickTerminalItems, arguments[2], "GLOWSTICKS"), "CFOAMGRENADES" => SetTerminalItemBoolean(Plugin.EnableCFoamGrenadeTerminalItems, arguments[2], "CFOAMGRENADES"), "CFOAMMINES" => SetTerminalItemBoolean(Plugin.EnableCFoamMineTerminalItems, arguments[2], "CFOAMMINES"), "MINES" => SetTerminalItemBoolean(Plugin.EnableExplosiveMineTerminalItems, arguments[2], "MINES"), "FOGREPELLERS" => SetTerminalItemBoolean(Plugin.EnableFogRepellerTerminalItems, arguments[2], "FOGREPELLERS"), "LOCKMELTERS" => SetTerminalItemBoolean(Plugin.EnableLockMelterTerminalItems, arguments[2], "LOCKMELTERS"), "FLASHLIGHTS" => SetTerminalItemBoolean(Plugin.EnableLongRangeFlashlightTerminalItems, arguments[2], "FLASHLIGHTS"), "I2LPSYRINGES" => SetTerminalItemBoolean(Plugin.EnableHealthSyringeTerminalItems, arguments[2], "I2LPSYRINGES"), "IIXSYRINGES" => SetTerminalItemBoolean(Plugin.EnableBoostSyringeTerminalItems, arguments[2], "IIXSYRINGES"), "CONSUMABLESINLIST" => SetTerminalItemBoolean(Plugin.ShowConsumablesInNativeList, arguments[2], "CONSUMABLESINLIST"), "PIPELINES" => SetBoolean(Plugin.EnablePipelines, arguments[2], "PIPELINES"), "HISTORY" => SetBoolean(Plugin.EnableHistorySearch, arguments[2], "HISTORY"), "HISTORYLIMIT" => SetInteger(Plugin.MaximumHistoryEntries, arguments[2], "HISTORYLIMIT", 10, 5000), "HISTORYVISIBLE" => SetInteger(Plugin.MaximumVisibleHistoryResults, arguments[2], "HISTORYVISIBLE", 3, 50), "HISTORYMODE" => SetHistoryPersistence(arguments[2]), "LANGUAGE" => SetLanguage(arguments[2]), "NEOFETCH" => SetBoolean(Plugin.ShowNeofetchOnTerminalStart, arguments[2], "NEOFETCH"), "NEOFETCHMODE" => SetNeofetchMode(arguments[2]), "IDLESCREEN" => SetIdleScreen(arguments[2]), "IDLECOLORS" => SetIdleScreenColorMode(arguments[2]), "BACKGROUND" => SetAppearanceBoolean(Plugin.EnableTerminalBackground, arguments[2], "BACKGROUND"), "IMAGEFLIPH" => SetAppearanceBoolean(Plugin.ImageFlipHorizontal, arguments[2], "IMAGEFLIPH"), "IMAGEFLIPV" => SetAppearanceBoolean(Plugin.ImageFlipVertical, arguments[2], "IMAGEFLIPV"), "IMAGEINTENSITY" => SetAppearanceInteger(Plugin.ImageIntensityPercent, arguments[2], "IMAGEINTENSITY", 1, 100), "IMAGEOPACITY" => SetAppearanceInteger(Plugin.ImageOpacityPercent, arguments[2], "IMAGEOPACITY", 0, 100), "IMAGEROTATION" => SetImageRotation(arguments[2]), "TEXTCOLOR" => SetTextColor(arguments[2]), "TEXTINTENSITY" => SetAppearanceInteger(Plugin.TerminalTextIntensityPercent, arguments[2], "TEXTINTENSITY", 1, 100), "DISTANCE" => SetDistance(arguments[2]), "MODE" => SetMode(arguments[2]), _ => Help(), }; } private static string SetTerminalItemBoolean(ConfigEntry entry, string value, string key) { string result = SetBoolean(entry, value, key); if ((value == "ON" || value == "OFF") ? true : false) { ConsumableTerminalRegistry.RefreshAll(); } return result; } private static string SetBoolean(ConfigEntry entry, string value, string key) { if ((!(value == "ON") && !(value == "OFF")) || 1 == 0) { return "INVALID VALUE FOR " + key + ". USE ON OR OFF."; } entry.Value = value == "ON"; return key + ": " + value; } private static string SetDistance(string value) { int result; bool flag = !int.TryParse(value, out result); if (!flag) { bool flag2 = ((result < 1 || result > 10) ? true : false); flag = flag2; } if (flag) { return "INVALID DISTANCE. USE A VALUE FROM 1 TO 10."; } Plugin.MaximumLevenshteinDistance.Value = result; return $"MAXIMUM LEVENSHTEIN DISTANCE: {result}"; } private static string SetInteger(ConfigEntry entry, string value, string key, int minimum, int maximum) { if (int.TryParse(value, out var result) && result >= minimum && result <= maximum) { entry.Value = result; return $"{key}: {result}"; } return $"INVALID {key}. USE A VALUE FROM {minimum} TO {maximum}."; } private static string SetMode(string value) { if (!Enum.TryParse(value, ignoreCase: true, out var result)) { return "INVALID MODE. USE COMMONPREFIX OR ARROWSELECTION."; } Plugin.AmbiguousMatches.Value = result; return "AMBIGUOUS MATCHES: " + result.ToString().ToUpperInvariant(); } private static string SetHistoryPersistence(string value) { if (!Enum.TryParse(value, ignoreCase: true, out var result)) { return LocalizationService.Text("history.mode_invalid"); } Plugin.HistoryPersistence.Value = result; HistoryStore.ReloadForPersistenceChange(); return LocalizationService.Text("history.mode_changed", result.ToString().ToUpperInvariant()); } private static string SetLanguage(string value) { if (!LocalizationService.TrySetLanguage(value)) { return LocalizationService.Text("config.language_missing", value.ToUpperInvariant()); } return LocalizationService.Text("config.language_changed", value.ToUpperInvariant()); } private static string SetNeofetchMode(string value) { if (!Enum.TryParse(value, ignoreCase: true, out var result)) { return "INVALID NEOFETCH MODE. USE NORMAL OR CUSTOM."; } Plugin.NeofetchDisplayMode.Value = result; NeofetchService.Reload(); return "NEOFETCH MODE: " + result.ToString().ToUpperInvariant(); } private static string SetIdleScreen(string value) { string result = SetBoolean(Plugin.EnableIdleScreenImage, value, "IDLESCREEN"); IdleScreenService.RefreshAll(); return result; } private static string SetIdleScreenColorMode(string value) { if (!Enum.TryParse(value, ignoreCase: true, out var result)) { return LocalizationService.Text("config.idle_colors_invalid"); } Plugin.IdleScreenColors.Value = result; IdleScreenService.Reload(); return LocalizationService.Text("config.idle_colors_changed", result.ToString().ToUpperInvariant()); } private static string SetAppearanceBoolean(ConfigEntry entry, string value, string key) { string result = SetBoolean(entry, value, key); if ((value == "ON" || value == "OFF") ? true : false) { RefreshAppearance(); } return result; } private static string SetAppearanceInteger(ConfigEntry entry, string value, string key, int minimum, int maximum) { string result = SetInteger(entry, value, key, minimum, maximum); if (int.TryParse(value, out var result2) && result2 >= minimum && result2 <= maximum) { RefreshAppearance(); } return result; } private static string SetImageRotation(string value) { int result; bool flag = !int.TryParse(value, out result); if (!flag) { bool flag2; switch (result) { case 0: case 90: case 180: case 270: flag2 = true; break; default: flag2 = false; break; } flag = !flag2; } if (flag) { return LocalizationService.Text("config.image_rotation_invalid"); } Plugin.ImageRotationDegrees.Value = result; RefreshAppearance(); return $"IMAGE ROTATION: {result}"; } private static string SetTextColor(string value) { Color val = default(Color); if (!value.Equals("DEFAULT", StringComparison.OrdinalIgnoreCase) && !ColorUtility.TryParseHtmlString(value.StartsWith('#') ? value : ("#" + value), ref val)) { return LocalizationService.Text("config.text_color_invalid"); } Plugin.TerminalTextColor.Value = value; TerminalAppearanceService.RefreshAll(); return "TEXT COLOR: " + value.ToUpperInvariant(); } private static string Section(string section) { return section switch { "SEARCH" => string.Join("\n", $"ENABLED: {Plugin.EnableFuzzySearch.Value}", $"COMMANDS: {Plugin.EnableCommandFuzzySearch.Value}", $"IDENTIFIERS: {Plugin.EnableIdentifierFuzzySearch.Value}", $"MODE: {Plugin.AmbiguousMatches.Value}", $"DISTANCE: {Plugin.MaximumLevenshteinDistance.Value}"), "HISTORY" => string.Join("\n", $"ENABLED: {Plugin.EnableHistorySearch.Value}", "MODE: " + Plugin.HistoryPersistence.Value.ToString().ToUpperInvariant(), $"LIMIT: {Plugin.MaximumHistoryEntries.Value}", $"VISIBLE RESULTS: {Plugin.MaximumVisibleHistoryResults.Value}"), "ITEMS" => string.Join("\n", $"ENABLED: {Plugin.EnableConsumableTerminalItems.Value}", $"GLOW STICKS: {Plugin.EnableGlowStickTerminalItems.Value}", $"C-FOAM GRENADES: {Plugin.EnableCFoamGrenadeTerminalItems.Value}", $"C-FOAM MINES: {Plugin.EnableCFoamMineTerminalItems.Value}", $"EXPLOSIVE MINES: {Plugin.EnableExplosiveMineTerminalItems.Value}", $"FOG REPELLERS: {Plugin.EnableFogRepellerTerminalItems.Value}", $"LOCK MELTERS: {Plugin.EnableLockMelterTerminalItems.Value}", $"FLASHLIGHTS: {Plugin.EnableLongRangeFlashlightTerminalItems.Value}", $"CONSUMABLES IN NATIVE LIST: {Plugin.ShowConsumablesInNativeList.Value}"), "APPEARANCE" => string.Join("\n", $"NEOFETCH: {Plugin.ShowNeofetchOnTerminalStart.Value}", $"IDLE SCREEN: {Plugin.EnableIdleScreenImage.Value}", $"BACKGROUND: {Plugin.EnableTerminalBackground.Value}", "TEXT COLOR: " + Plugin.TerminalTextColor.Value, $"TEXT INTENSITY: {Plugin.TerminalTextIntensityPercent.Value}%"), _ => Help(), }; } private static string ApplyProfile(string profile) { bool flag; switch (profile) { case "VANILLA": case "CONVENIENT": case "FULL": flag = true; break; default: flag = false; break; } if (!flag) { return "INVALID PROFILE. USE VANILLA, CONVENIENT OR FULL."; } flag = ((profile == "CONVENIENT" || profile == "FULL") ? true : false); bool value = flag; bool value2 = profile == "FULL"; Plugin.EnableFuzzySearch.Value = true; Plugin.EnableCommandFuzzySearch.Value = true; Plugin.EnableIdentifierFuzzySearch.Value = true; Plugin.EnableHistorySearch.Value = true; Plugin.EnablePipelines.Value = value; Plugin.EnableConsumableTerminalItems.Value = value; Plugin.ShowNeofetchOnTerminalStart.Value = value2; Plugin.EnableIdleScreenImage.Value = value2; Plugin.EnableTerminalBackground.Value = false; Plugin.Settings.Save(); ConsumableTerminalRegistry.RefreshAll(); RefreshAppearance(); return "PROFILE APPLIED: " + profile; } private static string ResetConfiguration(string section) { string normalized = section.ToUpperInvariant(); IEnumerable enumerable = from pair in (IEnumerable>)Plugin.Settings where normalized == "ALL" || pair.Key.Section.Equals(normalized, StringComparison.OrdinalIgnoreCase) || (normalized == "APPEARANCE" && pair.Key.Section == "Terminal Appearance") select pair.Value; int num = 0; foreach (ConfigEntryBase item in enumerable) { item.BoxedValue = item.DefaultValue; num++; } Plugin.Settings.Save(); LocalizationService.Reload(); ConsumableTerminalRegistry.RefreshAll(); RefreshAppearance(); if (num != 0) { return $"CONFIGURATION RESET: {normalized} ({num} SETTINGS)"; } return "UNKNOWN CONFIGURATION SECTION."; } private static void RefreshAppearance() { IdleScreenService.Reload(); TerminalAppearanceService.RefreshAll(); } private static string CurrentConfiguration() { return string.Join("\n", LocalizationService.Text("config.header"), "LANGUAGE: " + Plugin.Language.Value.ToUpperInvariant(), "ENABLED: " + Plugin.EnableFuzzySearch.Value.ToString().ToUpperInvariant(), "COMMANDS: " + Plugin.EnableCommandFuzzySearch.Value.ToString().ToUpperInvariant(), "IDENTIFIERS: " + Plugin.EnableIdentifierFuzzySearch.Value.ToString().ToUpperInvariant(), "AMBIGUOUS MATCHES: " + Plugin.AmbiguousMatches.Value.ToString().ToUpperInvariant(), $"MAXIMUM LEVENSHTEIN DISTANCE: {Plugin.MaximumLevenshteinDistance.Value}", "TERMINAL ITEMS: " + Plugin.EnableConsumableTerminalItems.Value.ToString().ToUpperInvariant(), "GLOW STICKS: " + Plugin.EnableGlowStickTerminalItems.Value.ToString().ToUpperInvariant(), "C-FOAM GRENADES: " + Plugin.EnableCFoamGrenadeTerminalItems.Value.ToString().ToUpperInvariant(), "C-FOAM MINES: " + Plugin.EnableCFoamMineTerminalItems.Value.ToString().ToUpperInvariant(), "MINES: " + Plugin.EnableExplosiveMineTerminalItems.Value.ToString().ToUpperInvariant(), "FOG REPELLERS: " + Plugin.EnableFogRepellerTerminalItems.Value.ToString().ToUpperInvariant(), "LOCK MELTERS: " + Plugin.EnableLockMelterTerminalItems.Value.ToString().ToUpperInvariant(), "LONG RANGE FLASHLIGHTS: " + Plugin.EnableLongRangeFlashlightTerminalItems.Value.ToString().ToUpperInvariant(), "I2-LP SYRINGES: " + Plugin.EnableHealthSyringeTerminalItems.Value.ToString().ToUpperInvariant(), "IIX SYRINGES: " + Plugin.EnableBoostSyringeTerminalItems.Value.ToString().ToUpperInvariant(), "CONSUMABLES IN NATIVE LIST: " + Plugin.ShowConsumablesInNativeList.Value.ToString().ToUpperInvariant(), "PIPELINES: " + Plugin.EnablePipelines.Value.ToString().ToUpperInvariant(), "HISTORY SEARCH: " + Plugin.EnableHistorySearch.Value.ToString().ToUpperInvariant(), "HISTORY MODE: " + Plugin.HistoryPersistence.Value.ToString().ToUpperInvariant(), $"HISTORY LIMIT: {Plugin.MaximumHistoryEntries.Value}", $"HISTORY VISIBLE RESULTS: {Plugin.MaximumVisibleHistoryResults.Value}", "NEOFETCH ON TERMINAL START: " + Plugin.ShowNeofetchOnTerminalStart.Value.ToString().ToUpperInvariant(), "NEOFETCH MODE: " + Plugin.NeofetchDisplayMode.Value.ToString().ToUpperInvariant(), "NEOFETCH NORMAL FILE: " + NeofetchService.DefaultFilePath, "NEOFETCH CUSTOM FILE: " + NeofetchService.FilePath, "IDLE SCREEN: " + Plugin.EnableIdleScreenImage.Value.ToString().ToUpperInvariant(), LocalizationService.Text("config.idle_colors_value", Plugin.IdleScreenColors.Value.ToString().ToUpperInvariant()), "IDLE SCREEN FILE: " + IdleScreenService.FilePath, "INTERACTIVE BACKGROUND: " + Plugin.EnableTerminalBackground.Value.ToString().ToUpperInvariant(), $"IMAGE INTENSITY: {Plugin.ImageIntensityPercent.Value}%", $"IMAGE OPACITY: {Plugin.ImageOpacityPercent.Value}%", $"IMAGE ROTATION: {Plugin.ImageRotationDegrees.Value}", "IMAGE FLIP HORIZONTAL: " + Plugin.ImageFlipHorizontal.Value.ToString().ToUpperInvariant(), "IMAGE FLIP VERTICAL: " + Plugin.ImageFlipVertical.Value.ToString().ToUpperInvariant(), "TEXT COLOR: " + Plugin.TerminalTextColor.Value.ToUpperInvariant(), $"TEXT INTENSITY: {Plugin.TerminalTextIntensityPercent.Value}%"); } private static string Help() { return string.Join("\n", LocalizationService.Text("config.help_header"), "CONFIG", "CONFIG RELOAD", "CONFIG SEARCH|HISTORY|ITEMS|APPEARANCE", "CONFIG PROFILE VANILLA|CONVENIENT|FULL", "CONFIG RESET [APPEARANCE|ALL]", "CONFIG ENABLED ON|OFF", "CONFIG COMMANDS ON|OFF", "CONFIG IDENTIFIERS ON|OFF", "CONFIG ITEMS ON|OFF", "CONFIG GLOWSTICKS ON|OFF", "CONFIG CFOAMGRENADES ON|OFF", "CONFIG CFOAMMINES ON|OFF", "CONFIG MINES ON|OFF", "CONFIG FOGREPELLERS ON|OFF", "CONFIG LOCKMELTERS ON|OFF", "CONFIG FLASHLIGHTS ON|OFF", "CONFIG I2LPSYRINGES ON|OFF", "CONFIG IIXSYRINGES ON|OFF", "CONFIG CONSUMABLESINLIST ON|OFF", "CONFIG PIPELINES ON|OFF", "CONFIG HISTORY ON|OFF", "CONFIG HISTORYMODE SESSION|DISK", "HISTORY CLEAR", "CONFIG HISTORYLIMIT 10-5000", "CONFIG HISTORYVISIBLE 3-50", "CONFIG LANGUAGE NAME", "CONFIG NEOFETCH ON|OFF", "CONFIG NEOFETCHMODE NORMAL|CUSTOM", "CONFIG IDLESCREEN ON|OFF", "CONFIG IDLECOLORS IMAGE|TERMINAL", "CONFIG BACKGROUND ON|OFF", "CONFIG IMAGEINTENSITY 1-100", "CONFIG IMAGEOPACITY 0-100", "CONFIG IMAGEROTATION 0|90|180|270", "CONFIG IMAGEFLIPH ON|OFF", "CONFIG IMAGEFLIPV ON|OFF", "CONFIG TEXTCOLOR DEFAULT|RRGGBB|RRGGBBAA", "CONFIG TEXTINTENSITY 1-100", "CONFIG MODE COMMONPREFIX|ARROWSELECTION", "CONFIG DISTANCE 1-10"); } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class HelpAndDocsCommandPatch { internal const string DocumentationUrl = "https://alexandermakunin.github.io/BetterTerminal/"; private static readonly HashSet Topics = new HashSet(StringComparer.OrdinalIgnoreCase) { "BETTERTERMINAL", "SEARCH", "HISTORY", "PIPELINES", "MARKERS", "CONSUMABLES", "APPEARANCE", "CONFIG", "STFO", "DOCS" }; [HarmonyPriority(800)] private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown string[] array = inputString.Trim().ToUpperInvariant().Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return true; } if (array[0] == CommandType.Help.Token() && array.Length == 2 && Topics.Contains(array[1])) { Write(__instance, inputString, HelpTopic(array[1])); return false; } if (array[0] == CommandType.BetterTerminal.Token()) { Write(__instance, inputString, (array.Length == 2 && array[1] == "STATUS") ? Status() : HelpTopic("BETTERTERMINAL")); return false; } if (array[0] != CommandType.Docs.Token()) { return true; } List list = new List(); list.Add(LocalizationService.Text("docs.url", "https://alexandermakunin.github.io/BetterTerminal/")); List list2 = list; if (array.Length == 2 && array[1] == "OPEN") { try { Process.Start(new ProcessStartInfo("https://alexandermakunin.github.io/BetterTerminal/") { UseShellExecute = true }); list2.Add(LocalizationService.Text("docs.opened")); } catch (Exception ex) { ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(20, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[DOCS] OPEN FAILED: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); } modLog.LogWarning(val); list2.Add(LocalizationService.Text("docs.open_failed")); } } else if (array.Length > 1) { list2.Add(LocalizationService.Text("docs.usage")); } Write(__instance, inputString, list2); return false; } private static IEnumerable HelpTopic(string topic) { return topic switch { "SEARCH" => Lines("help.search"), "HISTORY" => Lines("help.history"), "PIPELINES" => Lines("help.pipelines"), "MARKERS" => Lines("help.markers"), "CONSUMABLES" => Lines("help.consumables"), "APPEARANCE" => Lines("help.appearance"), "CONFIG" => Lines("help.config"), "STFO" => Lines("help.stfo"), "DOCS" => Lines("help.docs"), _ => Lines("help.betterterminal"), }; } private static IEnumerable Lines(string key) { return LocalizationService.Text(key).Split('\n'); } private static IEnumerable Status() { bool stfoInstalled = AppDomain.CurrentDomain.GetAssemblies().Any((Assembly assembly) => assembly.GetName().Name?.Equals("STFO", StringComparison.OrdinalIgnoreCase) ?? false); yield return "BETTERTERMINAL 1.1.3"; yield return "LANGUAGE: " + Plugin.Language.Value.ToUpperInvariant(); yield return $"FUZZY SEARCH: {Plugin.EnableFuzzySearch.Value}"; yield return $"PIPELINES: {Plugin.EnablePipelines.Value}"; yield return $"HISTORY: {Plugin.EnableHistorySearch.Value}"; yield return $"REGISTERED CONSUMABLES: {ConsumableTerminalRegistry.RegisteredCount}"; yield return $"ACTIVE MAP MARKERS: {ConsumableTerminalRegistry.ActiveMapMarkerCount}"; yield return "STFO: " + (stfoInstalled ? "INSTALLED" : "NOT INSTALLED"); yield return "CONFIG: " + Plugin.Settings.ConfigFilePath; yield return "LOCALIZATION: " + LocalizationService.DirectoryPath; yield return "DOCS: https://alexandermakunin.github.io/BetterTerminal/"; } private static void Write(LG_ComputerTerminalCommandInterpreter interpreter, string input, IEnumerable lines) { TerminalCommandOutput.WriteImmediate(interpreter, input.Trim().ToUpperInvariant(), lines); } } internal sealed class HistorySearchSession { internal string Query { get; set; } = string.Empty; internal int SelectedIndex { get; set; } internal List Matches { get; } = new List(); internal List RenderedLines { get; } = new List(); } internal static class HistorySearchManager { private static readonly Dictionary Sessions = new Dictionary(); internal static bool IsActive(uint terminalId) { return Sessions.ContainsKey(terminalId); } internal static bool TryOpen(LG_ComputerTerminal terminal) { if (!string.IsNullOrEmpty(terminal.m_currentLine) || HistoryStore.GetRecent().Count == 0) { return false; } Sessions[terminal.SyncID] = new HistorySearchSession(); terminal.m_command.ShowInputLine = false; terminal.m_command.ShowCustomLine = true; terminal.m_command.CustomLineBlinkEnabled = true; Refresh(terminal); return true; } internal static bool HandleUpdate(LG_ComputerTerminal terminal) { if (!Sessions.TryGetValue(terminal.SyncID, out HistorySearchSession value)) { return false; } if (InputMapper.GetButtonDown.Invoke((InputAction)20, (eFocusState)8)) { Close(terminal, null); return true; } bool flag = InputMapper.GetButtonDown.Invoke((InputAction)15, (eFocusState)8); bool flag2 = InputMapper.GetButtonDown.Invoke((InputAction)16, (eFocusState)8); if (flag || flag2) { if (value.Matches.Count > 0) { value.SelectedIndex = (value.SelectedIndex + ((!flag) ? 1 : (-1)) + value.Matches.Count) % value.Matches.Count; Render(terminal, value); } return true; } string inputString = Input.inputString; if (string.IsNullOrEmpty(inputString)) { return false; } string text = inputString; foreach (char c in text) { bool flag3; switch (c) { case '\b': if (value.Query.Length > 0) { HistorySearchSession historySearchSession = value; string query = value.Query; historySearchSession.Query = query.Substring(0, query.Length - 1); } continue; case '\n': case '\r': flag3 = true; break; default: flag3 = false; break; } if (flag3) { string selected = ((value.Matches.Count == 0) ? null : value.Matches[value.SelectedIndex]); Close(terminal, selected); return true; } if (!char.IsControl(c)) { value.Query += char.ToUpperInvariant(c); } } Refresh(terminal); return true; } private static void Refresh(LG_ComputerTerminal terminal) { HistorySearchSession session = Sessions[terminal.SyncID]; session.Matches.Clear(); HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); string[] source = session.Query.Split(' ', StringSplitOptions.RemoveEmptyEntries); IReadOnlyList recent = HistoryStore.GetRecent(); for (int num = recent.Count - 1; num >= 0; num--) { string command = recent[num]; if (command.Length != 0 && hashSet.Add(command) && !source.Any((string term) => !command.Contains(term, StringComparison.OrdinalIgnoreCase))) { session.Matches.Add(command); } } session.Matches.Sort(delegate(string left, string right) { bool flag = left.StartsWith(session.Query, StringComparison.OrdinalIgnoreCase); bool flag2 = right.StartsWith(session.Query, StringComparison.OrdinalIgnoreCase); return (flag != flag2) ? ((!flag) ? 1 : (-1)) : 0; }); session.SelectedIndex = Math.Clamp(session.SelectedIndex, 0, Math.Max(0, session.Matches.Count - 1)); Render(terminal, session); } private static void Render(LG_ComputerTerminal terminal, HistorySearchSession session) { RemoveRenderedLines(terminal.m_command, session); session.RenderedLines.Add(LocalizationService.Text("history.title")); int num = Math.Max(1, Plugin.MaximumVisibleHistoryResults.Value); int num2 = Math.Max(0, session.SelectedIndex - num + 1); int num3 = Math.Min(session.Matches.Count, num2 + num); for (int i = num2; i < num3; i++) { string text = ((i == session.SelectedIndex) ? "->" : " "); session.RenderedLines.Add(text + " " + session.Matches[i]); } if (session.Matches.Count == 0) { session.RenderedLines.Add(LocalizationService.Text("history.no_matches")); } foreach (string renderedLine in session.RenderedLines) { terminal.m_command.m_screenBuffer.Add(renderedLine); } terminal.m_command.CustomLineText = "HISTORY> " + session.Query; terminal.m_command.ResetLinesSinceCommand(); } private static void Close(LG_ComputerTerminal terminal, string? selected) { if (Sessions.Remove(terminal.SyncID, out HistorySearchSession value)) { RemoveRenderedLines(terminal.m_command, value); terminal.m_command.ShowCustomLine = false; terminal.m_command.CustomLineBlinkEnabled = false; terminal.m_command.CustomLineText = string.Empty; terminal.m_command.ShowInputLine = true; terminal.m_currentLine = selected ?? string.Empty; terminal.m_command.m_inputBufferStep = 0; } } private static void RemoveRenderedLines(LG_ComputerTerminalCommandInterpreter interpreter, HistorySearchSession session) { int num = interpreter.m_screenBuffer.Count - session.RenderedLines.Count; bool flag = num >= 0; int num2 = 0; while (flag && num2 < session.RenderedLines.Count) { flag = string.Equals(interpreter.m_screenBuffer[num + num2], session.RenderedLines[num2], StringComparison.Ordinal); num2++; } if (flag && session.RenderedLines.Count > 0) { interpreter.m_screenBuffer.RemoveRange(num, session.RenderedLines.Count); } else if (session.RenderedLines.Count > 0) { Plugin.ModLog.LogWarning((object)"[HISTORY] SCREEN BUFFER CHANGED; TEMPORARY HISTORY BLOCK WAS NOT REMOVED."); } session.RenderedLines.Clear(); } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class HistoryRecorderPatch { private static void Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { if (Plugin.EnableHistorySearch.Value && !HistoryStore.RecordingSuppressed && __instance.m_terminal != null && !TerminalInputReservationRegistry.IsReserved(__instance.m_terminal.SyncID)) { string[] array = inputString.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array.Length != 2 || !Enum.TryParse(array[0], ignoreCase: true, out var result) || result != CommandType.History || !Enum.TryParse(array[1], ignoreCase: true, out var result2) || result2 != HistoryAction.Clear) { HistoryStore.Record(inputString); } } } } internal static class HistoryStore { private static readonly List Entries = new List(); private static string FilePath => Path.Combine(Paths.ConfigPath, "BetterTerminal", "history.txt"); internal static bool RecordingSuppressed { get; set; } internal static void Initialize() { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown Entries.Clear(); if (Plugin.HistoryPersistence.Value == HistoryPersistenceMode.Session) { return; } try { Directory.CreateDirectory(Path.GetDirectoryName(FilePath)); if (File.Exists(FilePath)) { Entries.AddRange((from command in File.ReadLines(FilePath) select command.Trim().ToUpperInvariant() into command where command.Length > 0 select command).TakeLast(Plugin.MaximumHistoryEntries.Value)); } } catch (Exception ex) { ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(34, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HISTORY] COULD NOT LOAD HISTORY: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); } modLog.LogWarning(val); } } internal static IReadOnlyList GetRecent() { return Entries; } internal static void Record(string command) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown string text = command.Trim().ToUpperInvariant(); if (text.Length == 0) { return; } Entries.Add(text); int num = Entries.Count - Plugin.MaximumHistoryEntries.Value; if (num > 0) { Entries.RemoveRange(0, num); } if (Plugin.HistoryPersistence.Value != HistoryPersistenceMode.Disk) { return; } try { File.WriteAllLines(FilePath, Entries); } catch (Exception ex) { ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(34, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HISTORY] COULD NOT SAVE HISTORY: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); } modLog.LogWarning(val); } } internal static void Clear() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown Entries.Clear(); try { if (File.Exists(FilePath)) { File.Delete(FilePath); } } catch (Exception ex) { ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(36, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HISTORY] COULD NOT DELETE HISTORY: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); } modLog.LogWarning(val); } } internal static void ReloadForPersistenceChange() { Initialize(); } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class HistoryCommandPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { string[] array = inputString.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0 || !Enum.TryParse(array[0], ignoreCase: true, out var result) || result != CommandType.History) { return true; } string text; if (array.Length == 2 && Enum.TryParse(array[1], ignoreCase: true, out var result2) && result2 == HistoryAction.Clear) { HistoryStore.Clear(); text = LocalizationService.Text("history.cleared"); } else { text = LocalizationService.Text("history.usage"); } TerminalCommandOutput.WriteImmediate(__instance, inputString.Trim(), new string[1] { text }); return false; } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class LimitedListPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Expected O, but got Unknown string text = inputString.Trim().ToUpperInvariant(); string[] array = text.Split(' ', StringSplitOptions.RemoveEmptyEntries); CommandType result = default(CommandType); bool flag = array.Length != 3 || !Enum.TryParse(array[0], ignoreCase: true, out result); if (!flag) { bool flag2 = (uint)(result - 2) <= 1u; flag = !flag2; } if (flag) { return true; } if (!int.TryParse(array[2], out var result2) || result2 <= 0) { return true; } List list = TerminalItemSearch.Find(array[1]); int num = Math.Min(result2, list.Count); BepInExDebugLogInterpolatedStringHandler val; if (result == CommandType.Query) { ManualLogSource modLog = Plugin.ModLog; val = new BepInExDebugLogInterpolatedStringHandler(40, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[QUERY LIMIT] TYPE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(array[1]); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" REQUESTED="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(result2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" RETURNED="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(num); } modLog.LogDebug(val); if (num == 0) { WriteNoResults(__instance, text, array[1]); return false; } for (int i = 0; i < num; i++) { TerminalCommandOutput.EvaluateNativeWithoutHistory(__instance, CommandType.Query.Token() + " " + list[i].Identifier); } __instance.m_inputBuffer.Add(text); __instance.m_inputBufferStep = 0; return false; } __instance.m_inputBuffer.Add(text); __instance.m_inputBufferStep = 0; __instance.m_screenBuffer.Add(text); __instance.m_screenBuffer.Add(LocalizationService.Text("items.first_ids", num, array[1])); for (int j = 0; j < num; j++) { __instance.m_screenBuffer.Add(list[j].Identifier); } if (num == 0) { __instance.m_screenBuffer.Add(LocalizationService.Text("items.none", array[1])); } if (__instance.m_terminal != null) { __instance.m_terminal.m_currentLine = string.Empty; } __instance.ResetLinesSinceCommand(); ManualLogSource modLog2 = Plugin.ModLog; val = new BepInExDebugLogInterpolatedStringHandler(39, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LIST LIMIT] TYPE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(array[1]); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" REQUESTED="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(result2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" RETURNED="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(num); } modLog2.LogDebug(val); return false; } private static void WriteNoResults(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string itemType) { interpreter.m_inputBuffer.Add(commandLine); interpreter.m_inputBufferStep = 0; interpreter.m_screenBuffer.Add(commandLine); interpreter.m_screenBuffer.Add(LocalizationService.Text("items.none", itemType)); if (interpreter.m_terminal != null) { interpreter.m_terminal.m_currentLine = string.Empty; } interpreter.ResetLinesSinceCommand(); } } internal sealed record ModCommand(string Name, string DescriptionKey); internal static class ModCommands { private static readonly List All = new List { new ModCommand(CommandType.Config.Token(), "commands.config"), new ModCommand(CommandType.History.Token(), "commands.history_command"), new ModCommand(CommandType.Neofetch.Token(), "commands.neofetch"), new ModCommand(CommandType.IdleScreen.Token(), "commands.idlescreen"), new ModCommand(CommandType.Mark.Token(), "commands.mark"), new ModCommand(CommandType.Unmark.Token(), "commands.unmark"), new ModCommand(CommandType.BetterTerminal.Token(), "commands.betterterminal"), new ModCommand(CommandType.Docs.Token(), "commands.docs") }; internal static IEnumerable Names => All.Select((ModCommand command) => command.Name); internal static void Register(string name, string description) { if (!All.Any((ModCommand command) => command.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) { All.Add(new ModCommand(name.ToUpperInvariant(), description.ToUpperInvariant())); } } internal static string BuildCommandsSection() { List list = new List { string.Empty, "---------------- BETTERTERMINAL ----------------" }; foreach (ModCommand item in All) { list.Add($"{item.Name,-16} {LocalizationService.Text(item.DescriptionKey)}"); } list.Add(CommandType.Query.Token() + " TYPE_MIN-MAX " + LocalizationService.Text("commands.query_range")); list.Add(CommandType.Query.Token() + " TYPE COUNT " + LocalizationService.Text("commands.query_count")); list.Add(CommandType.List.Token() + " TYPE_MIN-MAX " + LocalizationService.Text("commands.list_range")); list.Add(CommandType.List.Token() + " TYPE COUNT " + LocalizationService.Text("commands.list_count")); list.Add($"{CommandType.List.Token()} | {CommandType.Where.Token()} FIELD VALUE | {CommandType.Sort.Token()} FIELD | {CommandType.Take.Token()} N"); list.Add(LocalizationService.Text("commands.pipeline_outputs")); list.Add("UP ON EMPTY LINE " + LocalizationService.Text("commands.history")); list.Add(LocalizationService.Text("commands.config_hint")); list.Add("------------------------------------------------"); return string.Join("\n", list); } } internal enum PipelineStage { Where, Sort, Take, Count, Query, Ping, Mark, Unmark } internal enum PipelineField { Text, Id, Type, Zone, Area, Status } internal sealed record PipelineItem(string Id, string Type, string Zone, string Area, string Status, iTerminalItem Item); internal enum PipelineDataType { Items, Text } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] [HarmonyPriority(800)] internal static class PipelineCommandPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown if (!Plugin.EnablePipelines.Value || !inputString.Contains('|')) { return true; } if (!CanHandle(inputString)) { return true; } int count = __instance.m_screenBuffer.Count; try { return Execute(__instance, inputString); } catch (Exception ex) { int num = __instance.m_screenBuffer.Count - count; if (num > 0) { __instance.m_screenBuffer.RemoveRange(count, num); } ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(59, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[PIPELINE] FAILED BEFORE COMPLETION; FALLING BACK TO GTFO: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex); } modLog.LogError(val); return true; } } private static bool Execute(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { string text = inputString.Trim().ToUpperInvariant(); string[] array = text.Split('|', StringSplitOptions.TrimEntries); if (array.Length < 2) { WriteError(__instance, text, LocalizationService.Text("pipeline.must_start_list")); return false; } if (!TryCreateSource(__instance, array[0], out PipelineDataType dataType, out List items, out List textLines, out string error)) { WriteError(__instance, text, error); return false; } bool flag = false; List list = new List(); for (int i = 1; i < array.Length; i++) { string[] array2 = array[i].Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array2.Length == 0) { continue; } if (!Enum.TryParse(array2[0], ignoreCase: true, out var result)) { if (PipelineExtensionRegistry.TryExecute(array2[0], array2, items, out PipelineExtensionResult result2)) { list.AddRange(result2.OutputLines); if (!result2.Succeeded) { TerminalCommandOutput.WriteImmediate(__instance, text, list); return false; } items = result2.Items; continue; } WriteError(__instance, text, LocalizationService.Text("pipeline.unknown_stage", array2[0])); return false; } switch (result) { case PipelineStage.Where: if (dataType == PipelineDataType.Text) { if (!TryApplyTextWhere(textLines, array[i], out textLines, out error)) { WriteError(__instance, text, error); return false; } } else if (!TryApplyWhere(items, array[i], out items, out error)) { WriteError(__instance, text, error); return false; } break; case PipelineStage.Sort: if (dataType == PipelineDataType.Text) { textLines = ((array2.Length == 2 && array2[1].Equals("DESC", StringComparison.OrdinalIgnoreCase)) ? textLines.OrderByDescending((string line) => line, StringComparer.OrdinalIgnoreCase).ToList() : textLines.OrderBy((string line) => line, StringComparer.OrdinalIgnoreCase).ToList()); } else if (!TryApplySort(items, array2, out items, out error)) { WriteError(__instance, text, error); return false; } break; case PipelineStage.Take: { if (array2.Length != 2 || !int.TryParse(array2[1], out var result3) || result3 < 0) { WriteError(__instance, text, "USE: TAKE N"); return false; } if (dataType == PipelineDataType.Text) { textLines = textLines.Take(result3).ToList(); } else { items = items.Take(result3).ToList(); } break; } case PipelineStage.Count: if (i != array.Length - 1) { WriteError(__instance, text, LocalizationService.Text("pipeline.count_last")); return false; } TerminalCommandOutput.WriteImmediate(__instance, text, new string[1] { $"COUNT: {((dataType == PipelineDataType.Text) ? textLines.Count : items.Count)}" }); return false; case PipelineStage.Query: if (dataType != PipelineDataType.Items) { WriteError(__instance, text, "QUERY REQUIRES AN ITEM STREAM."); return false; } if (i != array.Length - 1) { WriteError(__instance, text, LocalizationService.Text("pipeline.query_last")); return false; } flag = true; break; case PipelineStage.Ping: { if (dataType != PipelineDataType.Items) { WriteError(__instance, text, "PING REQUIRES AN ITEM STREAM."); return false; } if (i != array.Length - 1 || items.Count != 1) { WriteError(__instance, text, LocalizationService.Text("pipeline.ping_single")); return false; } if (!ConsumableTerminalRegistry.TryPlayPing(items[0].Id, out string message)) { items[0].Item.PlayPing(); message = LocalizationService.Text("pipeline.ping_started", items[0].Id); } TerminalCommandOutput.WriteImmediate(__instance, text, new string[1] { message }); return false; } case PipelineStage.Mark: { if (dataType != PipelineDataType.Items) { WriteError(__instance, text, "MARK REQUIRES AN ITEM STREAM."); return false; } if (i != array.Length - 1) { WriteError(__instance, text, LocalizationService.Text("pipeline.mark_last")); return false; } List list2 = new List(); foreach (PipelineItem item in items) { if (ConsumableTerminalRegistry.TrySetMapMarker(item.Id, item.Item, out string message2, replaceExisting: false)) { list2.Add(item.Id); } else { list.Add(message2); } } list.Add(LocalizationService.Text("pipeline.marked", list2.Count)); if (list2.Count > 1) { object[] array3 = new object[1]; array3[0] = list2[list2.Count - 1]; list.Add(LocalizationService.Text("pipeline.last_ping", array3)); } TerminalCommandOutput.WriteImmediate(__instance, text, list); return false; } case PipelineStage.Unmark: if (dataType != PipelineDataType.Items) { WriteError(__instance, text, "UNMARK REQUIRES AN ITEM STREAM."); return false; } if (i != array.Length - 1) { WriteError(__instance, text, LocalizationService.Text("pipeline.unmark_last")); return false; } foreach (PipelineItem item2 in items) { list.Add(ConsumableTerminalRegistry.ClearMapMarker(item2.Id)); } TerminalCommandOutput.WriteImmediate(__instance, text, list); return false; } } object obj; if (dataType != PipelineDataType.Text) { obj = (flag ? BuildQueryLines(__instance, items) : BuildListLines(items)); } else { IEnumerable enumerable = textLines; obj = enumerable; } IEnumerable second = (IEnumerable)obj; TerminalCommandOutput.WriteImmediate(__instance, text, list.Concat(second)); return false; } private static bool CanHandle(string inputString) { string[] array = inputString.Split('|', StringSplitOptions.TrimEntries); if (array.Length < 2 || array.Any(string.IsNullOrWhiteSpace)) { return false; } string[] array2 = array[0].Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (array2.Length == 0 || !Enum.TryParse(array2[0], ignoreCase: true, out var result) || result == CommandType.Unknown) { return false; } for (int i = 1; i < array.Length; i++) { string text = array[i].Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)[0]; if (!Enum.TryParse(text, ignoreCase: true, out var _) && !PipelineExtensionRegistry.IsRegistered(text)) { return false; } } return true; } private static bool TryCreateSource(LG_ComputerTerminalCommandInterpreter interpreter, string source, out PipelineDataType dataType, out List items, out List textLines, out string error) { //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) dataType = PipelineDataType.Items; items = new List(); textLines = new List(); error = string.Empty; string[] array = source.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0 || !Enum.TryParse(array[0], ignoreCase: true, out var result)) { error = LocalizationService.Text("pipeline.unknown_stage", array.FirstOrDefault() ?? string.Empty); return false; } if ((uint)(result - 7) <= 1u) { if (array.Length != 1) { error = "USE: " + result.ToString().ToUpperInvariant(); return false; } dataType = PipelineDataType.Text; textLines = CommandsListPatch.BuildLines(interpreter, result).ToList(); return true; } if (result != CommandType.List) { int count = interpreter.m_screenBuffer.Count; TerminalCommandOutput.EvaluateNativeWithoutHistory(interpreter, source); int num = interpreter.m_screenBuffer.Count - count; if (num > 0) { for (int i = count; i < interpreter.m_screenBuffer.Count; i++) { textLines.Add(interpreter.m_screenBuffer[i]); } interpreter.m_screenBuffer.RemoveRange(count, num); } dataType = PipelineDataType.Text; return true; } TerminalItemCategory terminalItemCategory = TerminalItemCategory.All; List list = new List(); foreach (string item in array.Skip(1)) { if (TryParseCategory(item, out var category)) { terminalItemCategory = category; } else { list.Add(item); } } ConsumableTerminalRegistry.RefreshAll(); LG_LevelInteractionManager current2 = LG_LevelInteractionManager.Current; Dictionary val = ((current2 != null) ? current2.m_terminalItemsByKeyString : null); if (val == null) { error = LocalizationService.Text("pipeline.registry_unavailable"); return false; } Enumerator enumerator2 = val.Keys.GetEnumerator(); while (enumerator2.MoveNext()) { string current3 = enumerator2.Current; string normalizedId = current3.ToUpperInvariant(); bool flag = ConsumableTerminalRegistry.IsConsumableIdentifier(normalizedId); if ((terminalItemCategory != TerminalItemCategory.Consumable || flag) && !(terminalItemCategory == TerminalItemCategory.Native && flag) && !list.Any((string filter) => !normalizedId.Contains(filter, StringComparison.OrdinalIgnoreCase))) { iTerminalItem val2 = val[current3]; AIG_CourseNode spawnNode = val2.SpawnNode; string zone = ((spawnNode == null) ? "UNKNOWN" : spawnNode.m_zone.Alias.ToString()); object area; if (spawnNode == null) { area = null; } else { LG_Area area2 = spawnNode.m_area; area = ((area2 != null) ? area2.m_geoArea : null); } string area3 = NormalizeArea((string?)area); items.Add(new PipelineItem(normalizedId, GetTypeFromId(normalizedId), zone, area3, ((object)val2.FloorItemStatus/*cast due to .constrained prefix*/).ToString().ToUpperInvariant(), val2)); } } items.Sort((PipelineItem left, PipelineItem right) => StringComparer.Ordinal.Compare(left.Id, right.Id)); return true; } private static bool TryApplyTextWhere(List source, string stage, out List result, out string error) { result = source; error = string.Empty; string text = stage.Substring(5).Trim(); string text2 = PipelineField.Text.ToString(); if (!text.StartsWith(text2, StringComparison.OrdinalIgnoreCase)) { error = "USE: WHERE TEXT VALUE, WHERE TEXT_VALUE OR WHERE TEXT-VALUE"; return false; } string text3 = text.Substring(text2.Length); bool flag = text3.Length < 2; if (!flag) { char c = text3[0]; bool flag2 = ((c == ' ' || c == '-' || c == '_') ? true : false); flag = !flag2; } if (flag) { error = "USE: WHERE TEXT VALUE, WHERE TEXT_VALUE OR WHERE TEXT-VALUE"; return false; } string value = text3.Substring(1).Trim().Trim('"'); if (value.Length == 0) { error = "WHERE TEXT REQUIRES A VALUE."; return false; } result = source.Where((string line) => line.Contains(value, StringComparison.OrdinalIgnoreCase)).ToList(); return true; } private static bool TryApplyWhere(List source, string stage, out List result, out string error) { result = source; error = string.Empty; if (!TryParseWhereExpression(stage.Substring(5).Trim(), out PipelineField field, out string value)) { error = "USE: WHERE FIELD VALUE, WHERE FIELD_VALUE OR WHERE FIELD-VALUE"; return false; } result = source.Where((PipelineItem item) => GetField(item, field).Contains(value, StringComparison.OrdinalIgnoreCase)).ToList(); return true; } private static bool TryApplySort(List source, string[] arguments, out List result, out string error) { result = source; error = string.Empty; int num = arguments.Length; bool flag = ((num < 2 || num > 3) ? true : false); if (flag || !Enum.TryParse(arguments[1], ignoreCase: true, out var field)) { error = "USE: SORT ID|TYPE|ZONE|AREA|STATUS [DESC]"; return false; } bool flag2 = arguments.Length == 3 && arguments[2] == "DESC"; if (arguments.Length == 3 && !flag2) { error = "SORT DIRECTION MUST BE DESC."; return false; } if (field == PipelineField.Zone) { result = (flag2 ? source.OrderByDescending((PipelineItem item) => ParseZone(item.Zone)).ToList() : source.OrderBy((PipelineItem item) => ParseZone(item.Zone)).ToList()); } else { result = (flag2 ? source.OrderByDescending((PipelineItem item) => GetField(item, field), StringComparer.OrdinalIgnoreCase).ToList() : source.OrderBy((PipelineItem item) => GetField(item, field), StringComparer.OrdinalIgnoreCase).ToList()); } return true; } private static IEnumerable BuildListLines(List items) { yield return $"{"ID",-30} {"TYPE",-24} {"ZONE",-8} {"AREA",-6} STATUS"; foreach (PipelineItem item in items) { yield return $"{item.Id,-30} {item.Type,-24} {item.Zone,-8} {item.Area,-6} {item.Status}"; } yield return $"COUNT: {items.Count}"; } private static bool TryParseWhereExpression(string expression, out PipelineField field, out string value) { field = PipelineField.Text; value = string.Empty; PipelineField[] values = Enum.GetValues(); for (int i = 0; i < values.Length; i++) { PipelineField pipelineField = values[i]; string text = pipelineField.ToString().ToUpperInvariant(); if (expression.StartsWith(text, StringComparison.Ordinal)) { string text2 = expression.Substring(text.Length); bool flag = text2.Length == 0; if (!flag) { char c = text2[0]; bool flag2 = ((c == ' ' || c == '-' || c == '_') ? true : false); flag = !flag2; } if (!flag) { field = pipelineField; value = text2.Substring(1).Trim().Trim('"') .Replace(' ', '_'); return value.Length > 0; } } } return false; } private static int ParseZone(string zone) { if (!int.TryParse(zone, out var result)) { return int.MaxValue; } return result; } private static string NormalizeArea(string? area) { if (string.IsNullOrWhiteSpace(area)) { return "UNKNOWN"; } string text = area.Trim().ToUpperInvariant(); if (text.StartsWith("AREA ", StringComparison.Ordinal)) { text = text.Substring(5); } return text.Replace(' ', '_'); } private static IEnumerable BuildQueryLines(LG_ComputerTerminalCommandInterpreter interpreter, List items) { foreach (PipelineItem item in items) { if (ConsumableTerminalRegistry.TryGetQueryLines(item.Id, out IReadOnlyList lines)) { foreach (string item2 in lines) { yield return item2; } yield return string.Empty; continue; } foreach (string item3 in CaptureNativeQuery(interpreter, item)) { yield return item3; } yield return string.Empty; } } private static IEnumerable CaptureNativeQuery(LG_ComputerTerminalCommandInterpreter interpreter, PipelineItem item) { int count = interpreter.m_screenBuffer.Count; TerminalCommandOutput.EvaluateNativeWithoutHistory(interpreter, CommandType.Query.Token() + " " + item.Id); int num = interpreter.m_screenBuffer.Count - count; if (num > 0) { string[] array = new string[num]; for (int i = 0; i < num; i++) { array[i] = interpreter.m_screenBuffer[count + i]; } interpreter.m_screenBuffer.RemoveRange(count, num); string[] array2 = array; for (int j = 0; j < array2.Length; j++) { yield return array2[j]; } } else { yield return "ID: " + item.Id; yield return "TYPE: " + item.Type; yield return "LOCATION: ZONE_" + item.Zone + " AREA_" + item.Area; yield return "STATUS: " + item.Status; } } private static bool TryParseCategory(string token, out TerminalItemCategory category) { if (Enum.TryParse(token.Trim().TrimEnd('S'), ignoreCase: true, out category) && category != TerminalItemCategory.All) { return true; } category = TerminalItemCategory.All; return false; } private static string GetTypeFromId(string id) { int num = id.LastIndexOf('_'); if (num <= 0 || !int.TryParse(id.Substring(num + 1), out var _)) { return id; } return id.Substring(0, num); } private static string GetField(PipelineItem item, PipelineField field) { return field switch { PipelineField.Text => item.Id, PipelineField.Id => item.Id, PipelineField.Type => item.Type, PipelineField.Zone => item.Zone, PipelineField.Area => item.Area, PipelineField.Status => item.Status, _ => string.Empty, }; } private static void WriteError(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string error) { TerminalCommandOutput.WriteImmediate(interpreter, commandLine, new string[1] { LocalizationService.Text("pipeline.error", error) }); } } internal sealed record PipelineExtensionResult(bool Succeeded, List Items, IReadOnlyList OutputLines); internal delegate PipelineExtensionResult PipelineExtensionHandler(string[] arguments, List items); internal static class PipelineExtensionRegistry { private static readonly Dictionary Handlers = new Dictionary(StringComparer.OrdinalIgnoreCase); internal static void Register(string stage, PipelineExtensionHandler handler) { Handlers[stage] = handler; } internal static bool IsRegistered(string stage) { return Handlers.ContainsKey(stage); } internal static bool TryExecute(string stage, string[] arguments, List items, out PipelineExtensionResult result) { if (Handlers.TryGetValue(stage, out PipelineExtensionHandler value)) { result = value(arguments, items); return true; } result = null; return false; } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class RangeQueryPatch { private static readonly Regex RangePattern = new Regex($"^({CommandType.Query.Token()}|{CommandType.List.Token()})\\s+([A-Z][A-Z0-9_]*)_(\\d+)-(\\d+)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant); private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown Match match = RangePattern.Match(inputString.Trim()); if (!match.Success) { return true; } CommandType commandType = Enum.Parse(match.Groups[1].Value, ignoreCase: true); string text = match.Groups[2].Value.ToUpperInvariant(); int minimum = int.Parse(match.Groups[3].Value); int maximum = int.Parse(match.Groups[4].Value); if (minimum > maximum) { int num = maximum; int num2 = minimum; maximum = num2; minimum = num; } List list = (from item in TerminalItemSearch.Find(text) where item.Number >= minimum && item.Number <= maximum select item).ToList(); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(31, 5, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(commandType.Token()); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" RANGE] TYPE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(text); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" MIN="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(minimum); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" MAX="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(maximum); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" COUNT="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(list.Count); } modLog.LogDebug(val); if (list.Count == 0) { WriteMessage(__instance, inputString.Trim().ToUpperInvariant(), LocalizationService.Text("items.none", $"{text}_{minimum}-{maximum}")); return false; } if (commandType == CommandType.Query) { foreach (TerminalItemMatch item in list) { TerminalCommandOutput.EvaluateNativeWithoutHistory(__instance, CommandType.Query.Token() + " " + item.Identifier); } RecordBatchCommand(__instance, inputString.Trim().ToUpperInvariant()); } else { WriteList(__instance, inputString.Trim().ToUpperInvariant(), LocalizationService.Text("items.range_ids", text, minimum, maximum), list); } return false; } private static void WriteList(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string header, List matches) { interpreter.m_inputBuffer.Add(commandLine); interpreter.m_inputBufferStep = 0; interpreter.m_screenBuffer.Add(commandLine); interpreter.m_screenBuffer.Add(header); foreach (TerminalItemMatch match in matches) { interpreter.m_screenBuffer.Add(match.Identifier); } if (interpreter.m_terminal != null) { interpreter.m_terminal.m_currentLine = string.Empty; } interpreter.ResetLinesSinceCommand(); } private static void WriteMessage(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string message) { interpreter.m_inputBuffer.Add(commandLine); interpreter.m_inputBufferStep = 0; interpreter.m_screenBuffer.Add(commandLine); interpreter.m_screenBuffer.Add(message); interpreter.ResetLinesSinceCommand(); } private static void RecordBatchCommand(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine) { interpreter.m_inputBuffer.Add(commandLine); interpreter.m_inputBufferStep = 0; } } internal static class TerminalCommandOutput { private const string Separator = "------------------------------------------------------------"; internal static void WriteImmediate(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, IEnumerable outputLines) { interpreter.m_inputBuffer.Add(commandLine); interpreter.m_inputBufferStep = 0; interpreter.m_screenBuffer.Add(string.Empty); interpreter.m_screenBuffer.Add(GetPrompt(interpreter) + commandLine); interpreter.m_screenBuffer.Add("------------------------------------------------------------"); foreach (string outputLine in outputLines) { interpreter.m_screenBuffer.Add(outputLine); } interpreter.m_screenBuffer.Add("------------------------------------------------------------"); interpreter.m_screenBuffer.Add(string.Empty); if (interpreter.m_terminal != null) { interpreter.m_terminal.m_currentLine = string.Empty; } interpreter.ResetLinesSinceCommand(); } internal static void WriteTransient(LG_ComputerTerminalCommandInterpreter interpreter, IEnumerable outputLines) { foreach (string outputLine in outputLines) { interpreter.m_screenBuffer.Add(outputLine); } if (interpreter.m_terminal != null) { interpreter.m_terminal.m_currentLine = string.Empty; } interpreter.m_inputBufferStep = 0; interpreter.ResetLinesSinceCommand(); } internal static void EvaluateNativeWithoutHistory(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine) { int count = interpreter.m_inputBuffer.Count; bool recordingSuppressed = HistoryStore.RecordingSuppressed; HistoryStore.RecordingSuppressed = true; try { interpreter.EvaluateInput(commandLine); } finally { HistoryStore.RecordingSuppressed = recordingSuppressed; int num = interpreter.m_inputBuffer.Count - count; if (num > 0) { interpreter.m_inputBuffer.RemoveRange(count, num); } interpreter.m_inputBufferStep = 0; } } private static string GetPrompt(LG_ComputerTerminalCommandInterpreter interpreter) { for (int num = interpreter.m_screenBuffer.Count - 1; num >= 0; num--) { string text = interpreter.m_screenBuffer[num]; if (text.StartsWith("\\\\", StringComparison.Ordinal)) { int num2 = text.IndexOf('\\', 2); if (num2 >= 0) { return text.Substring(0, num2 + 1); } } } return "\\\\ROOT\\"; } } internal static class TerminalInputReservationRegistry { private static readonly List> Reservations = new List>(); internal static void Register(Func reservation) { Reservations.Add(reservation); } internal static bool IsReserved(uint terminalId) { return Reservations.Any((Func reservation) => reservation(terminalId)); } } internal sealed record TerminalItemMatch(string Identifier, int Number); internal static class TerminalItemSearch { internal static List Find(string itemType) { List list = new List(); LG_LevelInteractionManager current = LG_LevelInteractionManager.Current; Dictionary val = ((current != null) ? current.m_terminalItemsByKeyString : null); if (val == null) { return list; } string text = itemType.Trim().ToUpperInvariant() + "_"; Enumerator enumerator = val.Keys.GetEnumerator(); while (enumerator.MoveNext()) { string text2 = enumerator.Current.ToUpperInvariant(); if (text2.StartsWith(text, StringComparison.Ordinal) && int.TryParse(text2.Substring(text.Length), out var result)) { list.Add(new TerminalItemMatch(text2, result)); } } list.Sort(delegate(TerminalItemMatch left, TerminalItemMatch right) { int num = left.Number.CompareTo(right.Number); return (num == 0) ? StringComparer.Ordinal.Compare(left.Identifier, right.Identifier) : num; }); return list; } } public class Levenshtein { public static int Compute(string s, string t) { if (string.IsNullOrEmpty(s)) { if (!string.IsNullOrEmpty(t)) { return t.Length; } return 0; } if (string.IsNullOrEmpty(t)) { return s.Length; } int length = s.Length; int length2 = t.Length; int[,] array = new int[length + 1, length2 + 1]; int num = 0; while (num <= length) { array[num, 0] = num++; } int num2 = 0; while (num2 <= length2) { array[0, num2] = num2++; } for (int i = 1; i <= length; i++) { for (int j = 1; j <= length2; j++) { int num3 = ((t[j - 1] != s[i - 1]) ? 1 : 0); array[i, j] = Math.Min(Math.Min(array[i - 1, j] + 1, array[i, j - 1] + 1), array[i - 1, j - 1] + num3); } } return array[length, length2]; } } internal static class LocalizationService { private static readonly Dictionary Fallback = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary Active = new Dictionary(StringComparer.OrdinalIgnoreCase); internal static string DirectoryPath { get; private set; } = string.Empty; internal static void Initialize() { DirectoryPath = Path.Combine(Paths.ConfigPath, "BetterTerminal", "Localization"); Directory.CreateDirectory(DirectoryPath); ExportBundledFiles(); Reload(); } internal static bool TrySetLanguage(string language) { string text = NormalizeLanguage(language); if (text.Length == 0 || !File.Exists(Path.Combine(DirectoryPath, text + ".json"))) { return false; } Plugin.Language.Value = text; Reload(); return true; } internal static void Reload() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown Fallback.Clear(); LoadBundledFile("en.json", Fallback); LoadFile(Path.Combine(DirectoryPath, "en.json"), Fallback, clearFirst: false); Active.Clear(); LoadFile(Path.Combine(DirectoryPath, NormalizeLanguage(Plugin.Language.Value) + ".json"), Active); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(40, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LOCALIZATION] LANGUAGE='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(Plugin.Language.Value); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' KEYS="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(Active.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" PATH='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(DirectoryPath); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog.LogInfo(val); } internal static string Text(string key, params object[] arguments) { string value; string value2; string text = ((Active.TryGetValue(key, out value) && value.Length > 0) ? value : ((Fallback.TryGetValue(key, out value2) && value2.Length > 0) ? value2 : key)); if (arguments.Length != 0) { return string.Format(text, arguments); } return text; } private static void LoadFile(string path, Dictionary destination, bool clearFirst = true) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown if (clearFirst) { destination.Clear(); } if (!File.Exists(path)) { return; } try { Dictionary dictionary = JsonSerializer.Deserialize>(File.ReadAllText(path)); if (dictionary == null) { return; } foreach (var (text3, value) in dictionary) { if (!text3.StartsWith('_')) { destination[text3] = value; } } } catch (Exception ex) { ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(34, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LOCALIZATION] FAILED TO LOAD '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(path); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); } modLog.LogError(val); } } private static void LoadBundledFile(string fileName, Dictionary destination) { Assembly assembly = typeof(LocalizationService).Assembly; string text = assembly.GetManifestResourceNames().FirstOrDefault((string name) => name.EndsWith("Localization." + fileName, StringComparison.OrdinalIgnoreCase)); if (text == null) { return; } using Stream utf8Json = assembly.GetManifestResourceStream(text); Dictionary dictionary = JsonSerializer.Deserialize>(utf8Json); if (dictionary == null) { return; } foreach (var (text4, value) in dictionary) { if (!text4.StartsWith('_')) { destination[text4] = value; } } } private static void ExportBundledFiles() { Assembly assembly = typeof(LocalizationService).Assembly; string[] array = new string[3] { "es.json", "en.json", "template.json" }; foreach (string fileName in array) { string text = Path.Combine(DirectoryPath, fileName); if (File.Exists(text)) { MergeMissingBundledKeys(assembly, fileName, text); continue; } string text2 = assembly.GetManifestResourceNames().FirstOrDefault((string name) => name.EndsWith("Localization." + fileName, StringComparison.OrdinalIgnoreCase)); if (text2 == null) { continue; } using Stream stream = assembly.GetManifestResourceStream(text2); using FileStream destination = File.Create(text); stream.CopyTo(destination); } } private static void MergeMissingBundledKeys(Assembly assembly, string fileName, string target) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown try { string text = assembly.GetManifestResourceNames().FirstOrDefault((string name) => name.EndsWith("Localization." + fileName, StringComparison.OrdinalIgnoreCase)); if (text == null) { return; } using Stream utf8Json = assembly.GetManifestResourceStream(text); Dictionary dictionary = JsonSerializer.Deserialize>(utf8Json); Dictionary dictionary2 = JsonSerializer.Deserialize>(File.ReadAllText(target)); if (dictionary == null || dictionary2 == null) { return; } bool flag = false; foreach (var (key, value) in dictionary) { if (!dictionary2.ContainsKey(key)) { dictionary2[key] = value; flag = true; } } if (flag) { File.WriteAllText(target, JsonSerializer.Serialize(dictionary2, new JsonSerializerOptions { WriteIndented = true })); } } catch (Exception ex) { ManualLogSource modLog = Plugin.ModLog; bool flag2 = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(49, 2, ref flag2); if (flag2) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LOCALIZATION] COULD NOT MERGE NEW KEYS INTO '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(target); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); } modLog.LogWarning(val); } } private static string NormalizeLanguage(string language) { return new string(language.Trim().ToLowerInvariant().Where(delegate(char character) { bool flag = char.IsLetterOrDigit(character); if (!flag) { bool flag2 = ((character == '-' || character == '_') ? true : false); flag = flag2; } return flag; }) .ToArray()); } } internal enum IdleScreenColorMode { Terminal, Image } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class IdleScreenCommandPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { string text = inputString.Trim().ToUpperInvariant(); string[] array = text.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0 || !Enum.TryParse(array[0], ignoreCase: true, out var result) || result != CommandType.IdleScreen) { return true; } string text2; if (array.Length != 2 || !(array[1] == "RELOAD")) { text2 = ((array.Length != 1) ? "USE: IDLESCREEN [RELOAD]" : ("IDLE SCREEN: " + (Plugin.EnableIdleScreenImage.Value ? "ON" : "OFF") + "\nFILE: " + IdleScreenService.FilePath)); } else { IdleScreenService.Reload(); text2 = "IDLE SCREEN IMAGE RELOADED."; } TerminalCommandOutput.WriteImmediate(__instance, text, text2.Split('\n')); return false; } } internal static class IdleScreenService { private sealed record ScreenOverride(Renderer Renderer, IReadOnlyDictionary? OriginalTextures, Material? OriginalMaterial, Material? ReplacementMaterial, MaterialPropertyBlock? OriginalPropertyBlock, MaterialPropertyBlock? ReplacementPropertyBlock, SpriteRenderer? SpriteRenderer, Sprite? OriginalSprite, Vector3 OriginalScale, Sprite? ReplacementSprite, Vector3 ReplacementScale, GameObject DisplayRoot, bool OriginalRootActive) { internal static ScreenOverride ForMaterial(Renderer renderer, IReadOnlyDictionary textures, MaterialPropertyBlock originalPropertyBlock, MaterialPropertyBlock replacementPropertyBlock, GameObject displayRoot, bool originalRootActive) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) return new ScreenOverride(renderer, textures, null, null, originalPropertyBlock, replacementPropertyBlock, null, null, Vector3.one, null, Vector3.one, displayRoot, originalRootActive); } internal static ScreenOverride ForImageMaterial(Renderer renderer, Material originalMaterial, Material replacementMaterial, MaterialPropertyBlock originalPropertyBlock, MaterialPropertyBlock replacementPropertyBlock, GameObject displayRoot, bool originalRootActive) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) return new ScreenOverride(renderer, null, originalMaterial, replacementMaterial, originalPropertyBlock, replacementPropertyBlock, null, null, Vector3.one, null, Vector3.one, displayRoot, originalRootActive); } internal static ScreenOverride ForSprite(Renderer renderer, SpriteRenderer spriteRenderer, Sprite? originalSprite, Vector3 originalScale, Sprite replacementSprite, Vector3 replacementScale, GameObject displayRoot, bool originalRootActive) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) return new ScreenOverride(renderer, null, null, null, null, null, spriteRenderer, originalSprite, originalScale, replacementSprite, replacementScale, displayRoot, originalRootActive); } } private const int MaximumImageBytes = 4194304; private const int MaximumDimension = 2048; private static readonly Dictionary Overrides = new Dictionary(); private static readonly Dictionary MaintainFrames = new Dictionary(); private static readonly HashSet Terminals = new HashSet(); private static bool _rendererDiagnosticsWritten; private static Texture2D? _texture; private static Texture2D? _rgbTexture; internal static string FilePath => Path.Combine(Paths.ConfigPath, "BetterTerminal", "idle-screen.png"); internal static Texture2D? BackgroundTexture => _rgbTexture ?? _texture; internal static IEnumerable RegisteredTerminals => Terminals.Where((LG_ComputerTerminal terminal) => terminal != null).ToArray(); internal static void Initialize() { Directory.CreateDirectory(Path.GetDirectoryName(FilePath)); ExportDefaultImage(); ReloadTexture(); } internal static void Register(LG_ComputerTerminal terminal) { Terminals.Add(terminal); } internal static void ApplyAfterFactoryBuild(LG_ComputerTerminal terminal) { Register(terminal); if (!terminal.m_hasInteractingPlayer && IsSleeping(terminal)) { Restore(terminal); Apply(terminal); } } internal static void Apply(LG_ComputerTerminal terminal) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_04ae: Expected O, but got Unknown //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04bd: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_04e4: Unknown result type (might be due to invalid IL or missing references) //IL_04e9: Unknown result type (might be due to invalid IL or missing references) //IL_04f4: Unknown result type (might be due to invalid IL or missing references) //IL_04fe: Expected O, but got Unknown //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_0566: Unknown result type (might be due to invalid IL or missing references) //IL_056d: Expected O, but got Unknown //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Expected O, but got Unknown //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_043a: Unknown result type (might be due to invalid IL or missing references) //IL_06d4: Unknown result type (might be due to invalid IL or missing references) //IL_06db: Expected O, but got Unknown //IL_06e3: Unknown result type (might be due to invalid IL or missing references) //IL_06ea: Expected O, but got Unknown //IL_0762: Unknown result type (might be due to invalid IL or missing references) //IL_0769: Expected O, but got Unknown if (!Plugin.EnableIdleScreenImage.Value || _texture == null || terminal.m_hasInteractingPlayer || Overrides.ContainsKey(terminal.SyncID)) { return; } LogRendererDiagnostics(terminal); Renderer val = FindIdleRenderer(terminal); bool flag = default(bool); if (val == null) { ManualLogSource modLog = Plugin.ModLog; BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(46, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[IDLE SCREEN] No renderer found for terminal "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(terminal.SyncID); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("."); } modLog.LogWarning(val2); return; } bool flag2 = ((Component)val).transform.IsChildOf(((Component)terminal).transform) && !((Component)val).transform.IsChildOf(terminal.m_loginScreen.transform); GameObject val3 = (flag2 ? ((Component)val).gameObject : terminal.m_loginScreen); bool activeSelf = val3.activeSelf; val3.SetActive(true); Material material = val.material; SpriteRenderer component = ((Component)val).gameObject.GetComponent(); BepInExDebugLogInterpolatedStringHandler val8; if (component != null) { Sprite sprite = component.sprite; Vector3 localScale = ((Component)component).transform.localScale; Bounds bounds; float num; if (sprite != null) { bounds = sprite.bounds; num = ((Bounds)(ref bounds)).size.x; } else { num = 1f; } float num2 = num; float num3; if (sprite != null) { bounds = sprite.bounds; num3 = ((Bounds)(ref bounds)).size.y; } else { num3 = 1f; } float num4 = num3; Vector2 val4 = FindDisplayWorldSize(terminal, component); float num5 = 100f; Sprite val5 = Sprite.Create(_texture, new Rect(0f, 0f, (float)((Texture)_texture).width, (float)((Texture)_texture).height), new Vector2(0.5f, 0.5f), num5); ((Object)val5).name = "BetterTerminal_IdleScreen_Sprite"; float num6 = (float)((Texture)_texture).width / num5; float num7 = (float)((Texture)_texture).height / num5; Transform parent = ((Component)component).transform.parent; Vector3 val6 = ((parent == null) ? Vector3.one : parent.lossyScale); Vector3 val7 = default(Vector3); ((Vector3)(ref val7))..ctor(val4.x / Math.Max(0.01f, num6 * Math.Abs(val6.x)), val4.y / Math.Max(0.01f, num7 * Math.Abs(val6.y)), 1f); component.sprite = val5; ((Component)component).transform.localScale = val7; ((Renderer)component).enabled = true; Overrides[terminal.SyncID] = ScreenOverride.ForSprite(val, component, sprite, localScale, val5, val7, val3, activeSelf); ManualLogSource modLog2 = Plugin.ModLog; val8 = new BepInExDebugLogInterpolatedStringHandler(123, 13, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("[IDLE SCREEN] Replaced sprite on terminal "); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(terminal.SyncID); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(", anchor '"); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(((Object)val).name); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("', "); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("original="); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(num2, "0.###"); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("x"); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(num4, "0.###"); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(", image="); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(((Texture)_texture).width); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("x"); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(((Texture)_texture).height); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(", "); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("display="); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(val4.x, "0.###"); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("x"); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(val4.y, "0.###"); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(", layer="); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(((Component)val).gameObject.layer); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(", "); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("active="); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(((Component)val).gameObject.activeInHierarchy); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(", enabled="); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(((Renderer)component).enabled); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(", "); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("bounds="); BepInExDebugLogInterpolatedStringHandler obj = val8; bounds = ((Renderer)component).bounds; ((BepInExLogInterpolatedStringHandler)obj).AppendFormatted(((Bounds)(ref bounds)).size.x, "0.###"); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("x"); BepInExDebugLogInterpolatedStringHandler obj2 = val8; bounds = ((Renderer)component).bounds; ((BepInExLogInterpolatedStringHandler)obj2).AppendFormatted(((Bounds)(ref bounds)).size.y, "0.###"); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("."); } modLog2.LogDebug(val8); return; } if (flag2 && Plugin.IdleScreenColors.Value == IdleScreenColorMode.Image) { Shader val9 = Shader.Find("Unlit/Transparent") ?? Shader.Find("Unlit/Texture") ?? Shader.Find("Sprites/Default"); if (val9 != null) { MaterialPropertyBlock val10 = new MaterialPropertyBlock(); val.GetPropertyBlock(val10); MaterialPropertyBlock val11 = new MaterialPropertyBlock(); val11.Clear(); Texture2D val12 = _rgbTexture ?? _texture; val11.SetTexture("_MainTex", (Texture)(object)val12); Material val13 = new Material(val9) { name = "BetterTerminal_IdleScreen_Material", mainTexture = (Texture)(object)val12 }; if (val13.HasProperty("_Color")) { val13.color = new Color(1f, 1f, 1f, 1f); } val.material = val13; val.SetPropertyBlock(val11); Overrides[terminal.SyncID] = ScreenOverride.ForImageMaterial(val, material, val13, val10, val11, val3, activeSelf); ManualLogSource modLog3 = Plugin.ModLog; val8 = new BepInExDebugLogInterpolatedStringHandler(87, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("[IDLE SCREEN] Applied RGB image to terminal "); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(terminal.SyncID); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(", "); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("renderer '"); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(((Object)val).name); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("', shader='"); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(((Object)val9).name); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("', "); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("pixelIntensity="); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(Plugin.ImageIntensityPercent.Value); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("%."); } modLog3.LogDebug(val8); return; } Plugin.ModLog.LogWarning((object)"[IDLE SCREEN] No RGB image shader found; using terminal colors."); } Dictionary dictionary = new Dictionary(); IEnumerable enumerable; if (!((Object)val).name.Equals("Display", StringComparison.OrdinalIgnoreCase) || !material.HasProperty("_EmissiveMap")) { IEnumerable texturePropertyNames = (IEnumerable)material.GetTexturePropertyNames(); enumerable = texturePropertyNames; } else { IEnumerable texturePropertyNames = new string[1] { "_EmissiveMap" }; enumerable = texturePropertyNames; } foreach (string item in enumerable) { Texture texture = material.GetTexture(item); dictionary[item] = texture; material.SetTexture(item, (Texture)(object)_texture); } if (dictionary.Count == 0) { dictionary["_MainTex"] = material.mainTexture; material.mainTexture = (Texture)(object)_texture; } MaterialPropertyBlock val14 = new MaterialPropertyBlock(); val.GetPropertyBlock(val14); MaterialPropertyBlock val15 = new MaterialPropertyBlock(); val.GetPropertyBlock(val15); foreach (string key in dictionary.Keys) { val15.SetTexture(key, (Texture)(object)_texture); } val.SetPropertyBlock(val15); Overrides[terminal.SyncID] = ScreenOverride.ForMaterial(val, dictionary, val14, val15, val3, activeSelf); ManualLogSource modLog4 = Plugin.ModLog; val8 = new BepInExDebugLogInterpolatedStringHandler(74, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("[IDLE SCREEN] Applied to terminal "); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(terminal.SyncID); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(", renderer '"); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(((Object)val).name); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("', "); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("shader='"); BepInExDebugLogInterpolatedStringHandler obj3 = val8; Shader shader = material.shader; ((BepInExLogInterpolatedStringHandler)obj3).AppendFormatted((shader != null) ? ((Object)shader).name : null); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("', properties=["); ((BepInExLogInterpolatedStringHandler)val8).AppendFormatted(string.Join(", ", dictionary.Keys)); ((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("]."); } modLog4.LogDebug(val8); } internal static void Restore(LG_ComputerTerminal terminal) { if (Overrides.Remove(terminal.SyncID, out ScreenOverride value)) { MaintainFrames.Remove(terminal.SyncID); Restore(value); } } internal static void Maintain(LG_ComputerTerminal terminal) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown if (!Overrides.TryGetValue(terminal.SyncID, out ScreenOverride value)) { return; } if (!value.DisplayRoot.activeSelf) { value.DisplayRoot.SetActive(true); } bool flag = default(bool); if (value.SpriteRenderer != null && value.ReplacementSprite != null) { if (!((Renderer)value.SpriteRenderer).enabled) { ((Renderer)value.SpriteRenderer).enabled = true; } if ((Object)(object)value.SpriteRenderer.sprite != (Object)(object)value.ReplacementSprite) { ManualLogSource modLog = Plugin.ModLog; BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(75, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[IDLE SCREEN:MAINTAIN] GTFO replaced the sprite on terminal "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(terminal.SyncID); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; restoring it."); } modLog.LogDebug(val); value.SpriteRenderer.sprite = value.ReplacementSprite; } ((Component)value.SpriteRenderer).transform.localScale = value.ReplacementScale; } else if (value.OriginalTextures != null) { if (!value.Renderer.enabled) { value.Renderer.enabled = true; } Material material = value.Renderer.material; foreach (string key in value.OriginalTextures.Keys) { material.SetTexture(key, (Texture)(object)_texture); } if (value.ReplacementPropertyBlock != null) { value.Renderer.SetPropertyBlock(value.ReplacementPropertyBlock); } } int value2; int num = ((!MaintainFrames.TryGetValue(terminal.SyncID, out value2)) ? 1 : (value2 + 1)); MaintainFrames[terminal.SyncID] = num; if (num == 30) { ManualLogSource modLog2 = Plugin.ModLog; BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(99, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[IDLE SCREEN:MAINTAIN] Terminal "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(terminal.SyncID); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" retained replacement for 30 frames; "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("active="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((Component)value.Renderer).gameObject.activeInHierarchy); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("enabled="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(value.Renderer.enabled); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("texture='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(GetAppliedTextureName(value)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'."); } modLog2.LogDebug(val); } } internal static void Reload() { RestoreAll(); ReloadTexture(); RefreshAll(); } internal static void RefreshAll() { if (!Plugin.EnableIdleScreenImage.Value) { RestoreAll(); return; } Terminals.RemoveWhere((LG_ComputerTerminal terminal) => terminal == null); LG_ComputerTerminal[] array = Terminals.ToArray(); foreach (LG_ComputerTerminal val in array) { if (!val.m_hasInteractingPlayer && IsSleeping(val)) { Apply(val); } } } private static bool IsSleeping(LG_ComputerTerminal terminal) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return string.Equals(((object)terminal.CurrentStateName/*cast due to .constrained prefix*/).ToString(), "Sleeping", StringComparison.OrdinalIgnoreCase); } private static void ReloadTexture() { //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown bool flag = default(bool); try { FileInfo fileInfo = new FileInfo(FilePath); if (!fileInfo.Exists || fileInfo.Length <= 0 || fileInfo.Length > 4194304) { ManualLogSource modLog = Plugin.ModLog; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(54, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[IDLE SCREEN] Image must be between 1 byte and "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(4194304); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" bytes."); } modLog.LogWarning(val); _texture = null; return; } byte[] array = File.ReadAllBytes(FilePath); Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val2, Il2CppStructArray.op_Implicit(array), false) || ((Texture)val2).width > 2048 || ((Texture)val2).height > 2048) { Object.Destroy((Object)(object)val2); ManualLogSource modLog2 = Plugin.ModLog; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(51, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[IDLE SCREEN] Invalid image or dimensions exceed "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(2048); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("x"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(2048); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); } modLog2.LogWarning(val); _texture = null; } else { ((Object)val2).name = "BetterTerminal_IdleScreen"; ((Texture)val2).wrapMode = (TextureWrapMode)1; ((Texture)val2).filterMode = (FilterMode)1; if (_texture != null) { Object.Destroy((Object)(object)_texture); } if (_rgbTexture != null) { Object.Destroy((Object)(object)_rgbTexture); } _texture = CreatePhysicalDisplayTexture(val2); Object.Destroy((Object)(object)val2); _rgbTexture = CreateRgbTexture(_texture); } } catch (Exception ex) { ManualLogSource modLog3 = Plugin.ModLog; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(36, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[IDLE SCREEN] Could not load image: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); } modLog3.LogWarning(val); _texture = null; } } private static Texture2D CreateRgbTexture(Texture2D source) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown float num = (float)Plugin.ImageIntensityPercent.Value / 100f; Color32[] array = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)source.GetPixels32()); for (int i = 0; i < array.Length; i++) { Color32 val = array[i]; array[i] = new Color32((byte)Math.Clamp((int)((float)(int)val.r * num), 0, 255), (byte)Math.Clamp((int)((float)(int)val.g * num), 0, 255), (byte)Math.Clamp((int)((float)(int)val.b * num), 0, 255), val.a); } Texture2D val2 = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, false) { name = "BetterTerminal_IdleScreen_RGB", wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; val2.SetPixels32(Il2CppStructArray.op_Implicit(array)); val2.Apply(false, false); return val2; } private static Texture2D CreatePhysicalDisplayTexture(Texture2D source) { //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) int width = ((Texture)source).width; int height = ((Texture)source).height; Color32[] array = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)source.GetPixels32()); Color32[] array2 = (Color32[])(object)new Color32[array.Length]; int num = (Plugin.ImageRotationDegrees.Value % 360 + 360) % 360; bool flag = ((num == 90 || num == 180 || num == 270) ? true : false); num = (flag ? num : 0); int num2 = (180 + num) % 360; flag = ((num2 == 90 || num2 == 270) ? true : false); int num3 = (flag ? height : width); flag = ((num2 == 90 || num2 == 270) ? true : false); int num4 = (flag ? width : height); array2 = (Color32[])(object)new Color32[num3 * num4]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int num5 = (Plugin.ImageFlipHorizontal.Value ? (width - 1 - j) : j); int num6 = (Plugin.ImageFlipVertical.Value ? (height - 1 - i) : i); int num7; int num8; switch (num2) { case 90: num7 = height - 1 - i; num8 = j; break; case 180: num7 = width - 1 - j; num8 = height - 1 - i; break; case 270: num7 = i; num8 = width - 1 - j; break; default: num7 = j; num8 = i; break; } array2[num8 * num3 + num7] = array[num6 * width + num5]; } } Texture2D val = new Texture2D(num3, num4, (TextureFormat)4, false) { name = "BetterTerminal_IdleScreen_Physical", wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; val.SetPixels32(Il2CppStructArray.op_Implicit(array2)); val.Apply(false, false); return val; } private static Renderer? FindIdleRenderer(LG_ComputerTerminal terminal) { return ((IEnumerable)((Component)terminal).gameObject.GetComponentsInChildren(true)).FirstOrDefault((Func)((Renderer renderer) => ((Object)renderer).name.Equals("Display", StringComparison.OrdinalIgnoreCase))); } private static string GetAppliedTextureName(ScreenOverride screenOverride) { SpriteRenderer? spriteRenderer = screenOverride.SpriteRenderer; object obj; if (spriteRenderer == null) { obj = null; } else { Sprite sprite = spriteRenderer.sprite; obj = ((sprite != null) ? sprite.texture : null); } Texture val = (Texture)obj; if (val != null) { return ((Object)val).name; } Material? replacementMaterial = screenOverride.ReplacementMaterial; Texture val2 = ((replacementMaterial != null) ? replacementMaterial.mainTexture : null); if (val2 != null) { return ((Object)val2).name; } if (screenOverride.OriginalTextures == null) { return "NONE"; } Material material = screenOverride.Renderer.material; foreach (string key in screenOverride.OriginalTextures.Keys) { Texture texture = material.GetTexture(key); if (texture != null) { return key + ":" + ((Object)texture).name; } } return "NONE"; } private static void LogRendererDiagnostics(LG_ComputerTerminal terminal) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Expected O, but got Unknown //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) if (_rendererDiagnosticsWritten) { return; } _rendererDiagnosticsWritten = true; (string, GameObject)[] array = new(string, GameObject)[3] { ("LOGIN", terminal.m_loginScreen), ("INTERFACE", terminal.m_interfaceScreen), ("SCREEN", terminal.m_screen) }; bool flag = default(bool); for (int i = 0; i < array.Length; i++) { var (text, val) = array[i]; if (val == null) { continue; } Renderer[] array2 = Il2CppArrayBase.op_Implicit(val.GetComponentsInChildren(true)); ManualLogSource modLog = Plugin.ModLog; BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(48, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[IDLE SCREEN:PROBE] ROOT="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(text); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" NAME='"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(((Object)val).name); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("ACTIVE="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(val.activeInHierarchy); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" COUNT="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(array2.Length); } modLog.LogInfo(val2); Renderer[] array3 = array2; foreach (Renderer val3 in array3) { SpriteRenderer component = ((Component)val3).gameObject.GetComponent(); object obj; if (component == null) { obj = null; } else { Sprite sprite = component.sprite; obj = ((sprite != null) ? sprite.texture : null); } if (obj == null) { Material material = val3.material; obj = ((material != null) ? material.mainTexture : null); } Texture val4 = (Texture)obj; string text2 = ((val4 == null) ? "NONE" : $"{((Object)val4).name}:{val4.width}x{val4.height}"); ManualLogSource modLog2 = Plugin.ModLog; val2 = new BepInExInfoLogInterpolatedStringHandler(119, 14, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[IDLE SCREEN:PROBE] ROOT="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(text); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" PATH='"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(GetHierarchyPath(((Component)val3).transform, val.transform)); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("NAME='"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(((Object)val3).name); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' TYPE="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(((object)val3).GetType().Name); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ACTIVE="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(((Component)val3).gameObject.activeInHierarchy); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("ENABLED="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(val3.enabled); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" LAYER="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(((Component)val3).gameObject.layer); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("BOUNDS="); BepInExInfoLogInterpolatedStringHandler obj2 = val2; Bounds bounds = val3.bounds; ((BepInExLogInterpolatedStringHandler)obj2).AppendFormatted(((Bounds)(ref bounds)).size.x, "0.###"); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("x"); BepInExInfoLogInterpolatedStringHandler obj3 = val2; bounds = val3.bounds; ((BepInExLogInterpolatedStringHandler)obj3).AppendFormatted(((Bounds)(ref bounds)).size.y, "0.###"); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("x"); BepInExInfoLogInterpolatedStringHandler obj4 = val2; bounds = val3.bounds; ((BepInExLogInterpolatedStringHandler)obj4).AppendFormatted(((Bounds)(ref bounds)).size.z, "0.###"); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("SHADER='"); BepInExInfoLogInterpolatedStringHandler obj5 = val2; Material material2 = val3.material; object obj6; if (material2 == null) { obj6 = null; } else { Shader shader = material2.shader; obj6 = ((shader != null) ? ((Object)shader).name : null); } if (obj6 == null) { obj6 = "NONE"; } ((BepInExLogInterpolatedStringHandler)obj5).AppendFormatted((string)obj6); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' TEXTURE='"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(text2); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("SPRITE='"); BepInExInfoLogInterpolatedStringHandler obj7 = val2; object obj8; if (component == null) { obj8 = null; } else { Sprite sprite2 = component.sprite; obj8 = ((sprite2 != null) ? ((Object)sprite2).name : null); } if (obj8 == null) { obj8 = "NONE"; } ((BepInExLogInterpolatedStringHandler)obj7).AppendFormatted((string)obj8); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' ORDER="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted((component != null) ? ((Renderer)component).sortingOrder : 0); } modLog2.LogInfo(val2); } } LogPhysicalScreenDiagnostics(terminal); } private static void LogPhysicalScreenDiagnostics(LG_ComputerTerminal terminal) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Expected O, but got Unknown GameObject gameObject = ((Component)terminal).gameObject; Renderer[] array = Il2CppArrayBase.op_Implicit(gameObject.GetComponentsInChildren(true)); Camera[] array2 = Il2CppArrayBase.op_Implicit(gameObject.GetComponentsInChildren(true)); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(50, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[IDLE SCREEN:PHYSICAL] ROOT='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((Object)gameObject).name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("RENDERERS="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(array.Length); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" CAMERAS="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(array2.Length); } modLog.LogInfo(val); Camera[] array3 = array2; foreach (Camera val2 in array3) { RenderTexture targetTexture = val2.targetTexture; ManualLogSource modLog2 = Plugin.ModLog; val = new BepInExInfoLogInterpolatedStringHandler(70, 5, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[IDLE SCREEN:PHYSICAL] CAMERA PATH='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(GetHierarchyPath(((Component)val2).transform, gameObject.transform)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ACTIVE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((Component)val2).gameObject.activeInHierarchy); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ENABLED="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((Behaviour)val2).enabled); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("TARGET='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((targetTexture != null) ? ((Object)targetTexture).name : null) ?? "NONE"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("SIZE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted((targetTexture == null) ? "NONE" : $"{((Texture)targetTexture).width}x{((Texture)targetTexture).height}"); } modLog2.LogInfo(val); } Renderer[] array4 = array; foreach (Renderer val3 in array4) { Material material = val3.material; string text = ((Object)val3).name.ToUpperInvariant(); List list = new List(); bool flag2 = false; foreach (string item in (Il2CppArrayBase)(object)material.GetTexturePropertyNames()) { Texture texture = material.GetTexture(item); if (texture != null) { flag2 |= ((Il2CppObjectBase)texture).TryCast() != null; list.Add($"{item}={((Object)texture).name}:{((object)texture).GetType().Name}:{texture.width}x{texture.height}"); } } bool flag3 = text.Contains("SCREEN") || text.Contains("MONITOR") || text.Contains("DISPLAY") || text.Contains("TERMINAL"); if (flag2 || flag3) { ManualLogSource modLog3 = Plugin.ModLog; val = new BepInExInfoLogInterpolatedStringHandler(98, 7, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[IDLE SCREEN:PHYSICAL] RENDERER PATH='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(GetHierarchyPath(((Component)val3).transform, gameObject.transform)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("NAME='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((Object)val3).name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' ACTIVE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((Component)val3).gameObject.activeInHierarchy); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ENABLED="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(val3.enabled); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("MATERIAL='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((Object)material).name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' SHADER='"); BepInExInfoLogInterpolatedStringHandler obj = val; Shader shader = material.shader; ((BepInExLogInterpolatedStringHandler)obj).AppendFormatted(((shader != null) ? ((Object)shader).name : null) ?? "NONE"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("TEXTURES=["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(string.Join(", ", list)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]"); } modLog3.LogInfo(val); } } } private static string GetHierarchyPath(Transform transform, Transform root) { Stack stack = new Stack(); for (Transform val = transform; val != null; val = val.parent) { stack.Push(((Object)val).name); if ((Object)(object)val == (Object)(object)root) { break; } } return string.Join("/", stack); } private static int Score(string name) { string text = name.ToUpperInvariant(); int num = 0; if (text.Contains("SCREEN")) { num += 4; } if (text.Contains("DISPLAY")) { num += 3; } if (text.Contains("LOGIN")) { num += 2; } return num; } private static Vector2 FindDisplayWorldSize(LG_ComputerTerminal terminal, SpriteRenderer target) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = ((Renderer)target).bounds; float num = Math.Max(0.01f, ((Bounds)(ref bounds)).size.x); bounds = ((Renderer)target).bounds; float num2 = Math.Max(0.01f, ((Bounds)(ref bounds)).size.y); GameObject[] array = (GameObject[])(object)new GameObject[3] { terminal.m_loginScreen, terminal.m_interfaceScreen, terminal.m_screen }; foreach (GameObject val in array) { if (val == null) { continue; } foreach (Renderer componentsInChild in val.GetComponentsInChildren(true)) { if (componentsInChild != null && !((Object)(object)componentsInChild == (Object)(object)target)) { bounds = componentsInChild.bounds; float x = ((Bounds)(ref bounds)).size.x; bounds = componentsInChild.bounds; float y = ((Bounds)(ref bounds)).size.y; if (!(x <= 0.01f) && !(y <= 0.01f)) { num = Math.Max(num, x); num2 = Math.Max(num2, y); } } } } Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(num * 0.92f, num2 * 0.92f); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val3 = new BepInExDebugLogInterpolatedStringHandler(45, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[IDLE SCREEN] Calculated full display size="); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(val2.x, "0.###"); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("x"); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(val2.y, "0.###"); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("."); } modLog.LogDebug(val3); return val2; } private static void RestoreAll() { foreach (ScreenOverride value in Overrides.Values) { Restore(value); } Overrides.Clear(); MaintainFrames.Clear(); } private static void Restore(ScreenOverride screenOverride) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (screenOverride.Renderer == null) { return; } if (screenOverride.SpriteRenderer != null) { screenOverride.SpriteRenderer.sprite = screenOverride.OriginalSprite; ((Component)screenOverride.SpriteRenderer).transform.localScale = screenOverride.OriginalScale; if (screenOverride.ReplacementSprite != null) { Object.Destroy((Object)(object)screenOverride.ReplacementSprite); } screenOverride.DisplayRoot.SetActive(screenOverride.OriginalRootActive); return; } Material val = screenOverride.Renderer.material; if (screenOverride.OriginalMaterial != null) { screenOverride.Renderer.material = screenOverride.OriginalMaterial; val = screenOverride.OriginalMaterial; } foreach (var (text2, val3) in screenOverride.OriginalTextures ?? new Dictionary()) { val.SetTexture(text2, val3); } if (screenOverride.OriginalPropertyBlock != null) { screenOverride.Renderer.SetPropertyBlock(screenOverride.OriginalPropertyBlock); } if (screenOverride.ReplacementMaterial != null) { Object.Destroy((Object)(object)screenOverride.ReplacementMaterial); } screenOverride.DisplayRoot.SetActive(screenOverride.OriginalRootActive); } private static void ExportDefaultImage() { if (File.Exists(FilePath)) { return; } using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("BetterTerminal.idle-screen.png"); if (stream == null) { return; } using FileStream destination = File.Create(FilePath); stream.CopyTo(destination); } } [HarmonyPatch(typeof(LG_ComputerTerminal), "Setup")] internal static class IdleScreenSetupPatch { private static void Postfix(LG_ComputerTerminal __instance) { IdleScreenService.Register(__instance); } } [HarmonyPatch(typeof(LG_ComputerTerminal), "OnFactoryBuildDone")] internal static class IdleScreenFactoryBuildPatch { private static void Postfix(LG_ComputerTerminal __instance) { IdleScreenService.ApplyAfterFactoryBuild(__instance); } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class NeofetchCommandPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { string text = inputString.Trim().ToUpperInvariant(); string[] array = text.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0 || !Enum.TryParse(array[0], ignoreCase: true, out var result) || result != CommandType.Neofetch) { return true; } if (array.Length > 2 || (array.Length == 2 && array[1] != "RELOAD")) { TerminalCommandOutput.WriteImmediate(__instance, text, new string[1] { "USE: NEOFETCH [RELOAD]" }); return false; } if (array.Length == 2) { NeofetchService.Reload(); } NeofetchService.Show(__instance.m_terminal); TerminalCommandOutput.WriteImmediate(__instance, text, new string[1] { (array.Length == 2) ? "NEOFETCH RELOADED." : "NEOFETCH PINNED." }); return false; } } internal enum NeofetchMode { Normal, Custom } internal static class NeofetchService { internal const int MaximumFileBytes = 16384; internal const int MaximumLines = 40; internal const int MaximumWidth = 120; private const int MaximumCombinedWidth = 120; private const int Gap = 3; private static readonly string[] DefaultArt = new string[15] { ".:::::::::::::::::::::::::::::::::::ii;.", ".:::::::::::::::::lli:::::::::::::::ii;.", ".:::::::::::::;I!!Iiit!I:::::::::::::::.", ".::::::::::::il:::iIIi::l;::::::::;IIII.", ".::::::::::::!;:::;;;;::ll;:::::::;:i;l.", ".::::::::::::l::iliiil::;!;:::::::;IIi:.", ".:::::::::::;!;::I!ll:::lI:::::::::;t!I.", ".::::::::::::il:::I!:::I!;:::::::::Il!I.", ".::::::::::::I;Il!lll!!I:::::::::::::::.", ".::::::::::I;::::::::::::::::::::::;;;;.", ".::::::::i;:::::::::::::::::::::::::::i.", ".,:,,,:;i,,,:,,,,,:,,,,:,:,:,,,,,:,,:I:.", ".:::::I;:::::::::::::::::::::::::::::::.", ".:::::I::::::::::::::::::::::::::::::::.", ".:::::::::::::::::::::::::::::::::::::::." }; private static readonly Dictionary> RenderedBlocks = new Dictionary>(); private static string[]? _normalArt; private static string[]? _customArt; internal static string FilePath => Path.Combine(Paths.ConfigPath, "BetterTerminal", "neofetch.txt"); internal static string DefaultFilePath => Path.Combine(Paths.ConfigPath, "BetterTerminal", "neofetch.default.txt"); internal static void Initialize() { string directoryName = Path.GetDirectoryName(FilePath); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } File.WriteAllLines(DefaultFilePath, DefaultArt); if (!File.Exists(FilePath)) { File.Copy(DefaultFilePath, FilePath); } Reload(); } internal static void Reload() { _normalArt = LoadArt(DefaultFilePath); _customArt = LoadArt(FilePath); } internal static IReadOnlyList Render(LG_ComputerTerminal? terminal = null) { string[] array = ((Plugin.NeofetchDisplayMode.Value == NeofetchMode.Custom) ? (_customArt ?? Array.Empty()) : (_normalArt ?? Array.Empty())); if (array.Length == 0) { array = new string[1] { "[NEOFETCH.TXT EMPTY OR INVALID]" }; } string[] array2 = new string[8] { "OS: GTFO TERMINAL OS", "HOST: " + GetHost(terminal), "CREATOR: ALEXANDERMAKUNIN", "MOD: BETTERTERMINAL", "VERSION: 1.1.3", "ZONE: " + GetZone(terminal), "LANGUAGE: " + Plugin.Language.Value.ToUpperInvariant(), "STFO: " + GetStfoStatus() }; int num = array.Max((string line) => line.Length); int num2 = array2.Max((string line) => line.Length); if (num + 3 + num2 > 120) { return array.Concat(new string[1] { string.Empty }).Concat(array2).ToArray(); } int num3 = Math.Max(array.Length, array2.Length); List list = new List(num3); for (int num4 = 0; num4 < num3; num4++) { string text = ((num4 < array.Length) ? array[num4] : string.Empty); string text2 = ((num4 < array2.Length) ? array2[num4] : string.Empty); list.Add((text2.Length == 0) ? text : (text.PadRight(num + 3) + text2)); } return list; } internal static void Show(LG_ComputerTerminal terminal) { if (terminal.m_command != null) { RemoveRenderedBlock(terminal); List list = new List(Render(terminal)); list.Add(string.Empty); for (int num = list.Count - 1; num >= 0; num--) { terminal.m_command.m_screenBuffer.Insert(0, list[num]); } RenderedBlocks[terminal.SyncID] = list; terminal.m_command.ResetLinesSinceCommand(); } } internal static void OnStateChanged(LG_ComputerTerminal terminal, object? state) { string a = state?.ToString() ?? string.Empty; bool flag = string.Equals(a, "PlayerInteracting", StringComparison.OrdinalIgnoreCase); if (string.Equals(a, "Awake", StringComparison.OrdinalIgnoreCase)) { IdleScreenService.Restore(terminal); TerminalAppearanceService.HideBackground(terminal); TerminalAppearanceService.RestoreTextColor(terminal); } else if (string.Equals(a, "Sleeping", StringComparison.OrdinalIgnoreCase)) { IdleScreenService.Restore(terminal); TerminalAppearanceService.HideBackground(terminal); TerminalAppearanceService.RestoreTextColor(terminal); if (!terminal.m_hasInteractingPlayer) { IdleScreenService.Apply(terminal); } } else if (flag) { IdleScreenService.Restore(terminal); TerminalAppearanceService.ShowBackground(terminal); TerminalAppearanceService.ApplyTextColor(terminal); if (Plugin.ShowNeofetchOnTerminalStart.Value) { Show(terminal); } } } private static void RemoveRenderedBlock(LG_ComputerTerminal terminal) { if (terminal.m_command == null || !RenderedBlocks.Remove(terminal.SyncID, out List value) || value.Count == 0) { return; } List screenBuffer = terminal.m_command.m_screenBuffer; for (int num = screenBuffer.Count - value.Count; num >= 0; num--) { bool flag = true; for (int i = 0; i < value.Count; i++) { if (!string.Equals(screenBuffer[num + i], value[i], StringComparison.Ordinal)) { flag = false; break; } } if (flag) { for (int j = 0; j < value.Count; j++) { screenBuffer.RemoveAt(num); } break; } } } private static string[] LoadArt(string path) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown bool flag = default(bool); try { FileInfo fileInfo = new FileInfo(path); if (!fileInfo.Exists || fileInfo.Length > 16384) { ManualLogSource modLog = Plugin.ModLog; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(37, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NEOFETCH] Invalid file size: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(fileInfo.Length); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" bytes."); } modLog.LogWarning(val); return Array.Empty(); } return File.ReadLines(path).Take(40).Select(SanitizeLine) .ToArray(); } catch (Exception ex) { ManualLogSource modLog2 = Plugin.ModLog; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(30, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NEOFETCH] Could not read '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(path); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); } modLog2.LogWarning(val); return Array.Empty(); } } private static string SanitizeLine(string line) { string text = new string(line.Where((char character) => character == '\t' || !char.IsControl(character)).ToArray()); text = text.Replace("\t", " "); if (text.Length > 120) { return text.Substring(0, 120); } return text; } private static string GetHost(LG_ComputerTerminal? terminal) { if (terminal == null) { return "TERMINAL_UNKNOWN"; } if (terminal.m_serialNumber > 0) { return $"TERMINAL_{terminal.m_serialNumber}"; } return $"TERMINAL_{terminal.SyncID}"; } private static string GetZone(LG_ComputerTerminal? terminal) { if (terminal == null) { return "UNKNOWN"; } AIG_CourseNode spawnNode = terminal.SpawnNode; if (((spawnNode != null) ? spawnNode.m_zone : null) != null) { return $"ZONE_{terminal.SpawnNode.m_zone.Alias}"; } return "UNKNOWN"; } private static string GetStfoStatus() { if ((object)Type.GetType("BetterTerminal.StfoPlugin, STFO", throwOnError: false) != null) { return "INSTALLED"; } return "NOT INSTALLED"; } } [HarmonyPatch] internal static class NeofetchTerminalStatePatch { private static MethodBase TargetMethod() { return AccessTools.GetDeclaredMethods(typeof(LG_ComputerTerminal)).First((MethodInfo method) => method.Name == "ChangeState" && method.GetParameters().Length != 0); } private static void Postfix(LG_ComputerTerminal __instance, object __0) { NeofetchService.OnStateChanged(__instance, __0); } } [HarmonyPatch(typeof(LG_ComputerTerminal), "OnInteract")] internal static class IdleScreenInteractionPatch { private static void Prefix(LG_ComputerTerminal __instance) { IdleScreenService.Restore(__instance); } } internal static class TerminalAppearanceService { private sealed record BackgroundOverride(GameObject GameObject, Sprite Sprite); private static readonly Dictionary Backgrounds = new Dictionary(); private static readonly Dictionary OriginalTextColors = new Dictionary(); internal static void ShowBackground(LG_ComputerTerminal terminal) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) HideBackground(terminal); if (!Plugin.EnableTerminalBackground.Value) { return; } Texture2D backgroundTexture = IdleScreenService.BackgroundTexture; if (backgroundTexture == null || terminal.m_interfaceScreen == null) { return; } SpriteRenderer val = ((IEnumerable)terminal.m_interfaceScreen.GetComponentsInChildren(true)).Where(delegate(SpriteRenderer renderer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Bounds bounds2 = ((Renderer)renderer).bounds; if (((Bounds)(ref bounds2)).size.x > 0.1f) { bounds2 = ((Renderer)renderer).bounds; return ((Bounds)(ref bounds2)).size.y > 0.1f; } return false; }).OrderByDescending(delegate(SpriteRenderer renderer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) Bounds bounds2 = ((Renderer)renderer).bounds; float x = ((Bounds)(ref bounds2)).size.x; bounds2 = ((Renderer)renderer).bounds; return x * ((Bounds)(ref bounds2)).size.y; }).FirstOrDefault(); if (val != null) { GameObject val2 = new GameObject("BetterTerminal_InteractiveBackground"); val2.layer = ((Component)val).gameObject.layer; val2.transform.SetParent(((Component)val).transform.parent, false); val2.transform.localPosition = ((Component)val).transform.localPosition; val2.transform.localRotation = ((Component)val).transform.localRotation * Quaternion.Euler(0f, 0f, 180f); SpriteRenderer obj = val2.AddComponent(); Sprite val3 = Sprite.Create(backgroundTexture, new Rect(0f, 0f, (float)((Texture)backgroundTexture).width, (float)((Texture)backgroundTexture).height), new Vector2(0.5f, 0.5f), 100f); ((Object)val3).name = "BetterTerminal_InteractiveBackground_Sprite"; obj.sprite = val3; ((Renderer)obj).sortingLayerID = ((Renderer)val).sortingLayerID; ((Renderer)obj).sortingOrder = ((Renderer)val).sortingOrder - 100; obj.color = new Color(1f, 1f, 1f, (float)Plugin.ImageOpacityPercent.Value / 100f); Bounds bounds = val3.bounds; float num = Math.Max(0.01f, ((Bounds)(ref bounds)).size.x); bounds = val3.bounds; float num2 = Math.Max(0.01f, ((Bounds)(ref bounds)).size.y); Transform transform = val2.transform; bounds = ((Renderer)val).bounds; float num3 = ((Bounds)(ref bounds)).size.x / num; bounds = ((Renderer)val).bounds; transform.localScale = new Vector3(num3, ((Bounds)(ref bounds)).size.y / num2, 1f); Backgrounds[terminal.SyncID] = new BackgroundOverride(val2, val3); } } internal static void HideBackground(LG_ComputerTerminal terminal) { if (Backgrounds.Remove(terminal.SyncID, out BackgroundOverride value)) { Object.Destroy((Object)(object)value.GameObject); Object.Destroy((Object)(object)value.Sprite); } } internal static void ApplyTextColor(LG_ComputerTerminal terminal) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) TextMeshPro text = terminal.m_text; if (text == null) { return; } if (!OriginalTextColors.ContainsKey(terminal.SyncID)) { OriginalTextColors[terminal.SyncID] = ((TMP_Text)text).color; } string text2 = Plugin.TerminalTextColor.Value.Trim(); if (text2.Equals("DEFAULT", StringComparison.OrdinalIgnoreCase)) { ((TMP_Text)text).color = OriginalTextColors[terminal.SyncID]; return; } if (!text2.StartsWith('#')) { text2 = "#" + text2; } Color color = default(Color); if (ColorUtility.TryParseHtmlString(text2, ref color)) { float num = (float)Plugin.TerminalTextIntensityPercent.Value / 100f; color.r *= num; color.g *= num; color.b *= num; ((TMP_Text)text).color = color; } } internal static void RestoreTextColor(LG_ComputerTerminal terminal) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) Color value; if (!Plugin.TerminalTextColor.Value.Trim().Equals("DEFAULT", StringComparison.OrdinalIgnoreCase)) { ApplyTextColor(terminal); } else if (terminal.m_text != null && OriginalTextColors.Remove(terminal.SyncID, out value)) { ((TMP_Text)terminal.m_text).color = value; } } internal static void RefreshAll() { foreach (LG_ComputerTerminal registeredTerminal in IdleScreenService.RegisteredTerminals) { if (registeredTerminal.m_hasInteractingPlayer) { ShowBackground(registeredTerminal); ApplyTextColor(registeredTerminal); } } } } } namespace BetterTerminal.TerminalItems { [HarmonyPatch(typeof(ConsumablePickup_Core), "Setup")] internal static class ConsumableDiagnosticPatch { private static void Postfix(ConsumablePickup_Core __instance, ItemDataBlock __0) { if (Plugin.LogConsumablePickups.Value) { Plugin.ModLog.LogInfo((object)("[CONSUMABLE] OBJECT='" + ((Object)__instance).name + "' PUBLIC_NAME='" + __0.publicName + "' TERMINAL_SHORT='" + __0.terminalItemShortName + "' " + $"TERMINAL_LONG='{__0.terminalItemLongName}' " + $"SYNC_ID={__0.syncID} " + $"REGISTERED_BY_GAME={__0.registerInTerminalSystem}")); } } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class ConsumableListPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { string[] array = inputString.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (array.Length != 2 || !Enum.TryParse(array[0], ignoreCase: true, out var result) || result != CommandType.List || !IsConsumableFilter(array[1])) { return true; } IReadOnlyList placedIdentifiers = ConsumableTerminalRegistry.GetPlacedIdentifiers(); IEnumerable outputLines = new string[1] { $"{"ID",-30} {"CATEGORY",-14} TYPE" }.Concat(placedIdentifiers.Select((string identifier) => $"{identifier,-30} {LocalizationService.Text("consumable.category"),-14} " + GetTypeName(identifier))).Append($"COUNT: {placedIdentifiers.Count}"); string commandLine = CommandType.List.Token() + " " + TerminalItemCategory.Consumable.ToString().ToUpperInvariant(); TerminalCommandOutput.WriteImmediate(__instance, commandLine, outputLines); return false; } private static bool IsConsumableFilter(string value) { if (Enum.TryParse(value.Trim().TrimEnd('S'), ignoreCase: true, out var result)) { return result == TerminalItemCategory.Consumable; } return false; } private static string GetTypeName(string identifier) { int num = identifier.LastIndexOf('_'); if (num <= 0) { return identifier; } return identifier.Substring(0, num); } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class ConsumableMapMarkerPatch { [HarmonyPriority(800)] private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { string[] array = inputString.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (array.Length == 0) { return true; } if (!Enum.TryParse(array[0], ignoreCase: true, out var result)) { return true; } switch (result) { case CommandType.Unmark: { string text2 = array.Length switch { 1 => ConsumableTerminalRegistry.ClearMapMarker(), 2 => ConsumableTerminalRegistry.ClearMapMarker(array[1]), _ => LocalizationService.Text("map_marker.unmark_usage"), }; string commandLine2 = ((array.Length == 2) ? (CommandType.Unmark.Token() + " " + array[1].ToUpperInvariant()) : inputString.Trim().ToUpperInvariant()); TerminalCommandOutput.WriteImmediate(__instance, commandLine2, new string[1] { text2 }); return false; } default: return true; case CommandType.Mark: { string text = ((array.Length == 2) ? GetMarkResult(array[1]) : LocalizationService.Text("map_marker.usage")); string commandLine = ((array.Length == 2) ? (CommandType.Mark.Token() + " " + array[1].ToUpperInvariant()) : inputString.Trim().ToUpperInvariant()); TerminalCommandOutput.WriteImmediate(__instance, commandLine, new string[1] { text }); return false; } } } private static string GetMarkResult(string identifier) { string text = identifier.Trim().ToUpperInvariant(); LG_LevelInteractionManager current = LG_LevelInteractionManager.Current; Dictionary val = ((current != null) ? current.m_terminalItemsByKeyString : null); if (val != null && val.ContainsKey(text)) { ConsumableTerminalRegistry.TrySetMapMarker(text, val[text], out string message); return message; } ConsumableTerminalRegistry.TrySetMapMarker(text, out string message2); return message2; } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] [HarmonyPriority(800)] internal static class ConsumablePingPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { string[] array = inputString.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (array.Length != 2 || !Enum.TryParse(array[0], ignoreCase: true, out var result) || result != CommandType.Ping) { return true; } if (!ConsumableTerminalRegistry.TryPlayPing(array[1], out string message)) { return true; } string commandLine = CommandType.Ping.ToString().ToUpperInvariant() + " " + array[1].ToUpperInvariant(); TerminalCommandOutput.WriteImmediate(__instance, commandLine, new string[1] { message }); return false; } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class ConsumableQueryPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown string[] array = inputString.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (array.Length != 2 || !Enum.TryParse(array[0], ignoreCase: true, out var result) || result != CommandType.Query) { return true; } ConsumableTerminalRegistry.RefreshAll(); if (!ConsumableTerminalRegistry.TryGetQueryLines(array[1], out IReadOnlyList lines)) { return true; } string commandLine = CommandType.Query.Token() + " " + array[1].ToUpperInvariant(); TerminalCommandOutput.WriteImmediate(__instance, commandLine, lines); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(37, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[CONSUMABLE QUERY] ID='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(array[1].ToUpperInvariant()); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' HANDLED=True"); } modLog.LogDebug(val); return false; } } internal enum ConsumableTerminalType { None, GlowStick, CFoamGrenade, CFoamMine, ExplosiveMine, FogRepeller, LockMelter, LongRangeFlashlight, HealthSyringe, BoostSyringe } internal sealed class ConsumableTerminalEntry { internal ConsumablePickup_Core Pickup { get; init; } internal ConsumableTerminalType Type { get; init; } internal bool IsPlaced { get; set; } internal bool WasPickedUp { get; set; } internal string Identifier { get; set; } = string.Empty; internal AIG_CourseNode? CourseNode { get; set; } internal LG_GenericTerminalItem? TerminalItem { get; set; } internal uint? MapGuiObjectId { get; set; } } internal static class ConsumableTerminalRegistry { private static readonly Dictionary Entries = new Dictionary(); private static readonly Dictionary NextIds = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary GenericMapMarkers = new Dictionary(StringComparer.OrdinalIgnoreCase); private static uint? _activeLocatorId; private static string? _activeLocatorIdentifier; private static uint? _temporaryPingLocatorId; private static float _temporaryPingExpiresAt; private const float TemporaryPingDurationSeconds = 5f; internal static int RegisteredCount => Entries.Values.Count((ConsumableTerminalEntry entry) => entry.TerminalItem != null); internal static int ActiveMapMarkerCount => GenericMapMarkers.Count + Entries.Values.Count((ConsumableTerminalEntry entry) => entry.MapGuiObjectId.HasValue); internal static bool IsConsumableIdentifier(string identifier) { string normalized = identifier.Trim().ToUpperInvariant(); return Entries.Values.Any((ConsumableTerminalEntry entry) => entry.TerminalItem != null && string.Equals(entry.Identifier, normalized, StringComparison.OrdinalIgnoreCase)); } internal static IReadOnlyList GetPlacedIdentifiers() { RefreshAll(); return (from entry in Entries.Values where entry.TerminalItem != null && entry.IsPlaced select entry.Identifier).OrderBy((string identifier) => identifier, StringComparer.Ordinal).ToArray(); } internal static void Remember(ConsumablePickup_Core pickup, ItemDataBlock data) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown ConsumableTerminalType consumableTerminalType = Classify(data.publicName); if (consumableTerminalType != ConsumableTerminalType.None) { Entries[((Object)pickup).GetInstanceID()] = new ConsumableTerminalEntry { Pickup = pickup, Type = consumableTerminalType }; ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(59, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TERMINAL ITEM] REMEMBERED OBJECT='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((Object)pickup).name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' TYPE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(consumableTerminalType); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("HAS_COURSE_NODE="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((ItemInLevel)pickup).CourseNode != null); } modLog.LogDebug(val); if (((ItemInLevel)pickup).CourseNode != null) { SetPlaced(pickup, placed: true); } } } internal static void SetPlaced(ConsumablePickup_Core pickup, bool placed, pPickupPlacement? placement = null) { if (Entries.TryGetValue(((Object)pickup).GetInstanceID(), out ConsumableTerminalEntry value)) { value.IsPlaced = placed; value.WasPickedUp = !placed; if (placed) { value.CourseNode = ResolveCourseNode(value, placement); } if (placed && IsEnabled(value.Type)) { Register(value); UpdateLocatorPosition(value); } else { Deregister(value); } } } internal static void RefreshAll() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(30, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TERMINAL ITEM] REFRESH COUNT="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(Entries.Count); } modLog.LogDebug(val); foreach (ConsumableTerminalEntry value in Entries.Values) { if (!value.IsPlaced && !value.WasPickedUp) { AIG_CourseNode val2 = ResolveCourseNode(value); if (val2 != null) { value.CourseNode = val2; value.IsPlaced = true; } } if (value.IsPlaced && IsEnabled(value.Type)) { Register(value); UpdateNativeListVisibility(value); UpdateLocatorPosition(value); } else { Deregister(value); } } } internal static void Reset() { ClearTemporaryPing(); ClearMapMarker(); Entries.Clear(); NextIds.Clear(); } internal static bool TrySetMapMarker(string identifier, out string message, bool replaceExisting = true) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) RefreshAll(); string normalized = identifier.Trim().ToUpperInvariant(); ConsumableTerminalEntry consumableTerminalEntry = Entries.Values.FirstOrDefault((ConsumableTerminalEntry candidate) => candidate.TerminalItem != null && candidate.IsPlaced && string.Equals(candidate.Identifier, normalized, StringComparison.OrdinalIgnoreCase)); if (consumableTerminalEntry?.TerminalItem == null) { message = LocalizationService.Text("map_marker.not_found", normalized); return false; } if (replaceExisting) { ClearMapMarker(); } uint terminalItemId = consumableTerminalEntry.TerminalItem.TerminalItemId; Vector3 position = ((Component)consumableTerminalEntry.Pickup).transform.position; if (MapDataManager.Current == null) { message = LocalizationService.Text("map_marker.unavailable"); return false; } if (consumableTerminalEntry.MapGuiObjectId.HasValue) { SetMapIconStatus(consumableTerminalEntry, (eCM_GuiObjectStatus)2); } else { consumableTerminalEntry.MapGuiObjectId = MapDataManager.WantToCreateCustomMapIcon((eCustomMapIconType)0, position, (eCM_GuiObjectStatus)2, terminalItemId); } GuiManager.AttemptSetLocatorBeacon(true, position, terminalItemId); GuiManager.AttemptSetTerminalPing(true, position, terminalItemId); _activeLocatorId = terminalItemId; _activeLocatorIdentifier = consumableTerminalEntry.Identifier; message = LocalizationService.Text("map_marker.set", consumableTerminalEntry.Identifier); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(48, 5, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[MAP MARKER] SET ID='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(consumableTerminalEntry.Identifier); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' LOCATOR_ID="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(terminalItemId); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("POSITION=("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(position.x, "0.###"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(","); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(position.y, "0.###"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(","); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(position.z, "0.###"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")"); } modLog.LogInfo(val); return true; } internal static string ClearMapMarker() { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown bool flag = false; foreach (ConsumableTerminalEntry value3 in Entries.Values) { if (value3.MapGuiObjectId.HasValue) { SetMapIconStatus(value3, (eCM_GuiObjectStatus)0); flag = true; } } foreach (KeyValuePair genericMapMarker in GenericMapMarkers) { genericMapMarker.Deconstruct(out var _, out var value); var (guiId, num) = value; HideMapIcon(guiId, num); GuiManager.RemoveLocatorBeaconIfActive(num); GuiManager.AttemptSetTerminalPing(false, Vector3.zero, num); flag = true; } GenericMapMarkers.Clear(); if (!_activeLocatorId.HasValue) { if (flag) { Plugin.ModLog.LogInfo((object)"[MAP MARKER] REMOVED ALL MAP ICONS"); return LocalizationService.Text("map_marker.removed", "ALL"); } return LocalizationService.Text("map_marker.none"); } uint value2 = _activeLocatorId.Value; string text = _activeLocatorIdentifier ?? value2.ToString(); GuiManager.RemoveLocatorBeaconIfActive(value2); GuiManager.AttemptSetTerminalPing(false, Vector3.zero, value2); _activeLocatorId = null; _activeLocatorIdentifier = null; ManualLogSource modLog = Plugin.ModLog; bool flag2 = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(38, 2, ref flag2); if (flag2) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[MAP MARKER] REMOVED ID='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(text); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' LOCATOR_ID="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(value2); } modLog.LogInfo(val); return LocalizationService.Text("map_marker.removed", text); } internal static bool TryPlayPing(string identifier, out string message) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) RefreshAll(); string normalized = identifier.Trim().ToUpperInvariant(); ConsumableTerminalEntry consumableTerminalEntry = Entries.Values.FirstOrDefault((ConsumableTerminalEntry candidate) => candidate.TerminalItem != null && candidate.IsPlaced && string.Equals(candidate.Identifier, normalized, StringComparison.OrdinalIgnoreCase)); if (consumableTerminalEntry?.TerminalItem == null) { message = LocalizationService.Text("map_marker.not_found", normalized); return false; } UpdateLocatorPosition(consumableTerminalEntry); Vector3 locatorBeaconPosition = consumableTerminalEntry.TerminalItem.LocatorBeaconPosition; uint terminalItemId = consumableTerminalEntry.TerminalItem.TerminalItemId; ClearTemporaryPing(); consumableTerminalEntry.TerminalItem.PlayPing(); GuiManager.AttemptSetLocatorBeacon(true, locatorBeaconPosition, terminalItemId); GuiManager.AttemptSetTerminalPing(true, locatorBeaconPosition, terminalItemId); _temporaryPingLocatorId = terminalItemId; _temporaryPingExpiresAt = Time.time + 5f; message = LocalizationService.Text("pipeline.ping_started", consumableTerminalEntry.Identifier); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(37, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[CONSUMABLE PING] ID='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(consumableTerminalEntry.Identifier); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("POSITION=("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(consumableTerminalEntry.TerminalItem.LocatorBeaconPosition.x, "0.###"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(","); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(consumableTerminalEntry.TerminalItem.LocatorBeaconPosition.y, "0.###"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(","); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(consumableTerminalEntry.TerminalItem.LocatorBeaconPosition.z, "0.###"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")"); } modLog.LogInfo(val); return true; } internal static void UpdateTemporaryPing() { if (_temporaryPingLocatorId.HasValue && Time.time >= _temporaryPingExpiresAt) { ClearTemporaryPing(); } } private static void ClearTemporaryPing() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown if (_temporaryPingLocatorId.HasValue) { uint locatorId = _temporaryPingLocatorId.Value; GuiManager.AttemptSetTerminalPing(false, Vector3.zero, locatorId); if (_activeLocatorId != locatorId && !GenericMapMarkers.Values.Any(((uint GuiId, uint LocatorId) marker) => marker.LocatorId == locatorId) && !Entries.Values.Any(delegate(ConsumableTerminalEntry entry) { if (entry.MapGuiObjectId.HasValue) { LG_GenericTerminalItem? terminalItem = entry.TerminalItem; if (terminalItem == null) { return false; } return terminalItem.TerminalItemId == locatorId; } return false; })) { GuiManager.RemoveLocatorBeaconIfActive(locatorId); } _temporaryPingLocatorId = null; _temporaryPingExpiresAt = 0f; ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(37, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[CONSUMABLE PING] EXPIRED LOCATOR_ID="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(locatorId); } modLog.LogDebug(val); } } internal static bool TrySetMapMarker(string identifier, iTerminalItem item, out string message, bool replaceExisting = true) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown string text = identifier.Trim().ToUpperInvariant(); if (TrySetMapMarker(text, out message, replaceExisting)) { return true; } if (MapDataManager.Current == null) { message = LocalizationService.Text("map_marker.unavailable"); return false; } if (replaceExisting) { ClearMapMarker(); } Vector3 locatorBeaconPosition = item.LocatorBeaconPosition; uint terminalItemId = item.TerminalItemId; uint num = MapDataManager.WantToCreateCustomMapIcon((eCustomMapIconType)0, locatorBeaconPosition, (eCM_GuiObjectStatus)2, terminalItemId); GenericMapMarkers[text] = (num, terminalItemId); GuiManager.AttemptSetLocatorBeacon(true, locatorBeaconPosition, terminalItemId); GuiManager.AttemptSetTerminalPing(true, locatorBeaconPosition, terminalItemId); message = LocalizationService.Text("map_marker.set", text); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(49, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[MAP MARKER] SET NATIVE ID='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(text); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' GUI_ID="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(num); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" LOCATOR_ID="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(terminalItemId); } modLog.LogInfo(val); return true; } internal static string ClearMapMarker(string identifier) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown string normalized = identifier.Trim().ToUpperInvariant(); if (GenericMapMarkers.Remove(normalized, out (uint, uint) value)) { HideMapIcon(value.Item1, value.Item2); GuiManager.RemoveLocatorBeaconIfActive(value.Item2); GuiManager.AttemptSetTerminalPing(false, Vector3.zero, value.Item2); return LocalizationService.Text("map_marker.removed", normalized); } ConsumableTerminalEntry consumableTerminalEntry = Entries.Values.FirstOrDefault((ConsumableTerminalEntry candidate) => string.Equals(candidate.Identifier, normalized, StringComparison.OrdinalIgnoreCase)); if (consumableTerminalEntry == null) { return LocalizationService.Text("map_marker.not_found", normalized); } if (_activeLocatorIdentifier != null && string.Equals(_activeLocatorIdentifier, normalized, StringComparison.OrdinalIgnoreCase)) { return ClearMapMarker(); } if (!consumableTerminalEntry.MapGuiObjectId.HasValue) { return LocalizationService.Text("map_marker.id_not_active", normalized); } SetMapIconStatus(consumableTerminalEntry, (eCM_GuiObjectStatus)0); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(26, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[MAP MARKER] REMOVED ID='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(normalized); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog.LogInfo(val); return LocalizationService.Text("map_marker.removed", normalized); } private static void SetMapIconStatus(ConsumableTerminalEntry entry, eCM_GuiObjectStatus status) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if (entry.MapGuiObjectId.HasValue && MapDataManager.Current != null) { uint value = entry.MapGuiObjectId.Value; MapDataManager.WantToSetGUIObjStatus(value, status, false, false); MapDataManager.SetGUIObjStatusLocally(value, status); MapDataManager.WantToSetGUIObjVisible(value, status); if (entry.TerminalItem != null) { MapDataManager.WantToSetCustomGUIObjStatusByTerminalItemId(entry.TerminalItem.TerminalItemId, status); } ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(53, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[MAP MARKER] STATUS ID='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(entry.Identifier); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' GUI_ID="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(value); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("STATUS="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(status); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" REGISTERED="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(MapDataManager.HasRegistredGUIObject(value)); } modLog.LogDebug(val); } } private static void HideMapIcon(uint guiId, uint locatorId) { if (MapDataManager.Current != null) { MapDataManager.WantToSetGUIObjStatus(guiId, (eCM_GuiObjectStatus)0, false, false); MapDataManager.SetGUIObjStatusLocally(guiId, (eCM_GuiObjectStatus)0); MapDataManager.WantToSetGUIObjVisible(guiId, (eCM_GuiObjectStatus)0); MapDataManager.WantToSetCustomGUIObjStatusByTerminalItemId(locatorId, (eCM_GuiObjectStatus)0); } } internal static bool TryGetQueryLines(string identifier, out IReadOnlyList lines) { string normalized = identifier.Trim().ToUpperInvariant(); ConsumableTerminalEntry consumableTerminalEntry = Entries.Values.FirstOrDefault((ConsumableTerminalEntry candidate) => candidate.TerminalItem != null && string.Equals(candidate.Identifier, normalized, StringComparison.OrdinalIgnoreCase)); if (consumableTerminalEntry == null) { lines = Array.Empty(); return false; } string text = ((consumableTerminalEntry.CourseNode == null) ? "UNKNOWN" : $"ZONE_{consumableTerminalEntry.CourseNode.m_zone.Alias}"); object obj; if (consumableTerminalEntry.CourseNode != null) { LG_Area area = consumableTerminalEntry.CourseNode.m_area; obj = NormalizeArea((area != null) ? area.m_geoArea : null); } else { obj = "UNKNOWN"; } string text2 = (string)obj; string text3 = (consumableTerminalEntry.IsPlaced ? "AVAILABLE" : "PICKED UP"); lines = new string[10] { GetDisplayName(consumableTerminalEntry.Type), string.Empty, "ID: " + consumableTerminalEntry.Identifier, "CATEGORY: " + LocalizationService.Text("consumable.category"), "TYPE: " + GetDisplayName(consumableTerminalEntry.Type), "LOCATION: " + text, "AREA: AREA_" + text2, "STATUS: " + text3, "USE: " + LocalizationService.Text(GetUsageKey(consumableTerminalEntry.Type)), "PING: AVAILABLE WHILE THE ITEM IS PLACED IN THE LEVEL" }; return true; } private static void Register(ConsumableTerminalEntry entry) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown if (entry.TerminalItem == null && entry.CourseNode != null) { if (string.IsNullOrEmpty(entry.Identifier)) { entry.Identifier = GetNextIdentifier(GetPrefix(entry.Type)); } LG_GenericTerminalItem val = ((Component)entry.Pickup).gameObject.AddComponent(); string text = $"ZONE_{entry.CourseNode.m_zone.Alias}"; LG_Area area = entry.CourseNode.m_area; string text2 = NormalizeArea((area != null) ? area.m_geoArea : null); val.Setup(entry.Identifier, entry.CourseNode); val.LocatorBeaconPosition = ((Component)entry.Pickup).transform.position; val.FloorItemType = (eFloorInventoryObjectType)7; val.FloorItemStatus = (eFloorInventoryObjectStatus)0; val.FloorItemLocation = text; val.ShowInFloorInventory = Plugin.ShowConsumablesInNativeList.Value; val.m_detailedInfo = new List(); val.m_detailedInfo.Add("TYPE: " + GetDisplayName(entry.Type)); val.m_detailedInfo.Add("LOCATION: " + text + " AREA_" + text2); entry.TerminalItem = val; ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(38, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[TERMINAL ITEM] REGISTERED ID='"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(entry.Identifier); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' TYPE="); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(entry.Type); } modLog.LogInfo(val2); } } private static void UpdateNativeListVisibility(ConsumableTerminalEntry entry) { if (entry.TerminalItem != null) { entry.TerminalItem.ShowInFloorInventory = Plugin.ShowConsumablesInNativeList.Value; } } private static void UpdateLocatorPosition(ConsumableTerminalEntry entry) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if (entry.TerminalItem != null && entry.IsPlaced) { Vector3 position = ((Component)entry.Pickup).transform.position; entry.TerminalItem.LocatorBeaconPosition = position; ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(43, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TERMINAL ITEM] LOCATOR ID='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(entry.Identifier); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("POSITION=("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(position.x, "0.###"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(","); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(position.y, "0.###"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(","); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(position.z, "0.###"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")"); } modLog.LogDebug(val); } } private static void Deregister(ConsumableTerminalEntry entry) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown if (entry.TerminalItem != null) { if (_activeLocatorId == entry.TerminalItem.TerminalItemId) { ClearMapMarker(); } entry.MapGuiObjectId = null; LG_LevelInteractionManager.DeregisterTerminalItem(((Il2CppObjectBase)entry.TerminalItem).Cast()); ManualLogSource modLog = Plugin.ModLog; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(34, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TERMINAL ITEM] DEREGISTERED ID='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(entry.TerminalItem.TerminalItemKey); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog.LogInfo(val); Object.Destroy((Object)(object)entry.TerminalItem); entry.TerminalItem = null; } } private static string GetNextIdentifier(string prefix) { int value; int num = ((!NextIds.TryGetValue(prefix, out value)) ? 1 : value); LG_LevelInteractionManager current = LG_LevelInteractionManager.Current; Dictionary val = ((current != null) ? current.m_terminalItemsByKeyString : null); string text; do { text = $"{prefix}_{num:000}"; num++; } while (val != null && val.ContainsKey(text)); NextIds[prefix] = num; return text; } private static AIG_CourseNode? ResolveCourseNode(ConsumableTerminalEntry entry, pPickupPlacement? placement = null) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) AIG_CourseNode result = default(AIG_CourseNode); if (Dimension.TryGetCourseNodeFromPos(((Component)entry.Pickup).transform.position, ref result)) { return result; } pPickupPlacement val = (pPickupPlacement)(((??)placement) ?? entry.Pickup.m_sync.GetCurrentState().placement); AIG_CourseNode result2 = default(AIG_CourseNode); if (!((pCourseNode)(ref val.node)).TryGet(ref result2)) { return null; } return result2; } private static string GetDisplayName(ConsumableTerminalType type) { return type switch { ConsumableTerminalType.GlowStick => "GLOW STICK", ConsumableTerminalType.CFoamGrenade => "C-FOAM GRENADE", ConsumableTerminalType.CFoamMine => "C-FOAM TRIPMINE", ConsumableTerminalType.ExplosiveMine => "EXPLOSIVE TRIPMINE", ConsumableTerminalType.FogRepeller => "FOG REPELLER", ConsumableTerminalType.LockMelter => "LOCK MELTER", ConsumableTerminalType.LongRangeFlashlight => "LONG RANGE FLASHLIGHT", ConsumableTerminalType.HealthSyringe => "I2-LP SYRINGE", ConsumableTerminalType.BoostSyringe => "IIX SYRINGE", _ => "CONSUMABLE", }; } private static string GetUsageKey(ConsumableTerminalType type) { return type switch { ConsumableTerminalType.GlowStick => "consumable.use.glow_stick", ConsumableTerminalType.CFoamGrenade => "consumable.use.cfoam_grenade", ConsumableTerminalType.CFoamMine => "consumable.use.cfoam_mine", ConsumableTerminalType.ExplosiveMine => "consumable.use.explosive_mine", ConsumableTerminalType.FogRepeller => "consumable.use.fog_repeller", ConsumableTerminalType.LockMelter => "consumable.use.lock_melter", ConsumableTerminalType.LongRangeFlashlight => "consumable.use.long_range_flashlight", ConsumableTerminalType.HealthSyringe => "consumable.use.health_syringe", ConsumableTerminalType.BoostSyringe => "consumable.use.boost_syringe", _ => "consumable.use.unknown", }; } private static string NormalizeArea(string? area) { if (string.IsNullOrWhiteSpace(area)) { return "UNKNOWN"; } string text = area.Trim().ToUpperInvariant(); if (text.StartsWith("AREA ", StringComparison.Ordinal)) { text = text.Substring(5); } return text.Replace(' ', '_'); } private static ConsumableTerminalType Classify(string publicName) { string text = publicName.ToUpperInvariant(); if (text != null) { if (text.StartsWith("GLOW STICK", StringComparison.Ordinal)) { return ConsumableTerminalType.GlowStick; } switch (text) { case "C-FOAM GRENADE": return ConsumableTerminalType.CFoamGrenade; case "C-FOAM TRIPMINE": return ConsumableTerminalType.CFoamMine; case "EXPLOSIVE TRIP MINE": return ConsumableTerminalType.ExplosiveMine; case "FOG REPELLER": return ConsumableTerminalType.FogRepeller; case "LOCK MELTER": return ConsumableTerminalType.LockMelter; case "LONG RANGE FLASHLIGHT": return ConsumableTerminalType.LongRangeFlashlight; case "I2-LP SYRINGE": return ConsumableTerminalType.HealthSyringe; case "IIX SYRINGE": return ConsumableTerminalType.BoostSyringe; } } return ConsumableTerminalType.None; } private static bool IsEnabled(ConsumableTerminalType type) { bool flag = Plugin.EnableConsumableTerminalItems.Value; if (flag) { flag = type switch { ConsumableTerminalType.GlowStick => Plugin.EnableGlowStickTerminalItems.Value, ConsumableTerminalType.CFoamGrenade => Plugin.EnableCFoamGrenadeTerminalItems.Value, ConsumableTerminalType.CFoamMine => Plugin.EnableCFoamMineTerminalItems.Value, ConsumableTerminalType.ExplosiveMine => Plugin.EnableExplosiveMineTerminalItems.Value, ConsumableTerminalType.FogRepeller => Plugin.EnableFogRepellerTerminalItems.Value, ConsumableTerminalType.LockMelter => Plugin.EnableLockMelterTerminalItems.Value, ConsumableTerminalType.LongRangeFlashlight => Plugin.EnableLongRangeFlashlightTerminalItems.Value, ConsumableTerminalType.HealthSyringe => Plugin.EnableHealthSyringeTerminalItems.Value, ConsumableTerminalType.BoostSyringe => Plugin.EnableBoostSyringeTerminalItems.Value, _ => false, }; } return flag; } private static string GetPrefix(ConsumableTerminalType type) { return type switch { ConsumableTerminalType.GlowStick => "GLOW_STICK", ConsumableTerminalType.CFoamGrenade => "C_FOAM_GRENADE", ConsumableTerminalType.CFoamMine => "C_FOAM_MINE", ConsumableTerminalType.ExplosiveMine => "MINE", ConsumableTerminalType.FogRepeller => "FOG_REPELLER", ConsumableTerminalType.LockMelter => "LOCK_MELTER", ConsumableTerminalType.LongRangeFlashlight => "LONG_RANGE_FLASHLIGHT", ConsumableTerminalType.HealthSyringe => "I2_LP_SYRINGE", ConsumableTerminalType.BoostSyringe => "IIX_SYRINGE", _ => throw new ArgumentOutOfRangeException("type"), }; } } [HarmonyPatch(typeof(ConsumablePickup_Core), "Setup")] internal static class ConsumableRegistrationSetupPatch { private static void Postfix(ConsumablePickup_Core __instance, ItemDataBlock __0) { ConsumableTerminalRegistry.Remember(__instance, __0); } } [HarmonyPatch(typeof(ConsumablePickup_Core), "OnFactoryCullingSetupDone")] internal static class ConsumableRegistrationFactoryReadyPatch { private static void Postfix(ConsumablePickup_Core __instance) { ConsumableTerminalRegistry.SetPlaced(__instance, placed: true); } } [HarmonyPatch(typeof(LG_ComputerTerminal), "OnFactoryBuildDone")] internal static class ConsumableRegistrationTerminalReadyPatch { private static void Postfix() { ConsumableTerminalRegistry.RefreshAll(); } } [HarmonyPatch(typeof(LG_ComputerTerminal), "Update")] internal static class ConsumableTemporaryPingUpdatePatch { private static void Postfix() { ConsumableTerminalRegistry.UpdateTemporaryPing(); } } [HarmonyPatch(typeof(ConsumablePickup_Core), "OnSyncStateChange")] internal static class ConsumableRegistrationStatePatch { private static void Postfix(ConsumablePickup_Core __instance, ePickupItemStatus __0, pPickupPlacement __1) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) ConsumableTerminalRegistry.SetPlaced(__instance, (int)__0 == 0, __1); } } [HarmonyPatch(typeof(ItemInLevel), "OnPlacedInLevel")] internal static class ConsumableRegistrationPlacedPatch { private static void Postfix(ItemInLevel __instance) { ConsumablePickup_Core val = ((Il2CppObjectBase)__instance).TryCast(); if (val != null) { ConsumableTerminalRegistry.SetPlaced(val, placed: true); } } } [HarmonyPatch(typeof(LG_LevelInteractionManager), "OnLevelCleanup")] internal static class ConsumableRegistrationResetPatch { private static void Postfix() { ConsumableTerminalRegistry.Reset(); } } }