Decompiled source of Interactive Terminal API v1.2.0

BepInEx/plugins/InteractiveTerminalAPI/InteractiveTerminalAPI.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using InteractiveTerminalAPI.Compat;
using InteractiveTerminalAPI.Input;
using InteractiveTerminalAPI.Misc.Util;
using InteractiveTerminalAPI.NetcodePatcher;
using InteractiveTerminalAPI.Patches.TerminalComponents;
using InteractiveTerminalAPI.UI;
using InteractiveTerminalAPI.UI.Application;
using InteractiveTerminalAPI.UI.Cursor;
using InteractiveTerminalAPI.UI.Hierarchy;
using InteractiveTerminalAPI.UI.Page;
using InteractiveTerminalAPI.UI.Screen;
using InteractiveTerminalAPI.Util;
using LethalCompanyInputUtils.Api;
using Microsoft.CodeAnalysis;
using MoreShipUpgrades.Misc;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MoreShipUpgrades.Misc
{
	public class PluginConfig
	{
		public PluginConfig(ConfigFile file)
		{
		}
	}
}
namespace InteractiveTerminalAPI
{
	[BepInPlugin("WhiteSpike.InteractiveTerminalAPI", "Interactive Terminal API", "1.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static readonly Harmony harmony = new Harmony("WhiteSpike.InteractiveTerminalAPI");

		internal static readonly ManualLogSource mls = Logger.CreateLogSource("Interactive Terminal API");

		public static PluginConfig Config;

		private void Awake()
		{
			InputUtils_Compat.Init();
			PatchMainVersion();
			mls.LogInfo((object)"Interactive Terminal API 1.2.0 has been loaded successfully.");
		}

		internal static void PatchMainVersion()
		{
			PatchVitalComponents();
		}

		private static void PatchVitalComponents()
		{
			try
			{
				harmony.PatchAll(typeof(Keybinds));
				harmony.PatchAll(typeof(TerminalPatcher));
				mls.LogInfo((object)"Game managers have been patched");
			}
			catch (Exception ex)
			{
				mls.LogError((object)"An error has occurred patching the game managers...");
				mls.LogError((object)ex);
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "InteractiveTerminalAPI";

		public const string PLUGIN_NAME = "MoreShipUpgrades";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace InteractiveTerminalAPI.Util
{
	internal static class TerminalNodeUtils
	{
		private static Terminal terminal;

		private static readonly Dictionary<string, TerminalNode> retrievedTerminalNodes = new Dictionary<string, TerminalNode>();

		private const string HELP_NOUN = "help";

		private const string INFO_VERB = "info";

		private const string SHOVEL_NOUN = "shovel";

		public static Terminal GetTerminal()
		{
			if ((Object)(object)terminal == (Object)null)
			{
				terminal = GameObject.Find("TerminalScript").GetComponent<Terminal>();
			}
			return terminal;
		}

		internal static TerminalKeyword FindTerminalKeyword(string word)
		{
			TerminalKeyword obj = GetTerminal().CheckForExactSentences(word);
			if ((Object)(object)obj == (Object)null)
			{
				Plugin.mls.LogError((object)("Couldn't find terminal node for the word \"" + word + "\""));
			}
			return obj;
		}

		internal static TerminalNode GetItemInfoTerminalNode(string word)
		{
			TerminalNode val = retrievedTerminalNodes.GetValueOrDefault(word, null);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			TerminalKeyword val2 = GetTerminal().ParseWord("info", 2);
			for (int i = 0; i < val2.compatibleNouns.Length; i++)
			{
				if (!((Object)(object)val == (Object)null))
				{
					break;
				}
				if (!(val2.compatibleNouns[i].noun.word != word))
				{
					val = val2.compatibleNouns[i].result;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.mls.LogError((object)("Couldn't find info terminal node for item \"" + word + "\""));
			}
			if (!retrievedTerminalNodes.ContainsKey(word))
			{
				retrievedTerminalNodes[word] = val;
			}
			return val;
		}

		internal static TerminalNode GetSpecialTerminalNodeByWord(string word)
		{
			TerminalNode valueOrDefault = retrievedTerminalNodes.GetValueOrDefault(word, null);
			if ((Object)(object)valueOrDefault != (Object)null)
			{
				return valueOrDefault;
			}
			valueOrDefault = FindTerminalKeyword(word).specialKeywordResult;
			if (!retrievedTerminalNodes.ContainsKey(word))
			{
				retrievedTerminalNodes[word] = valueOrDefault;
			}
			return valueOrDefault;
		}

		internal static void UpdateTextToNode(ref TerminalNode node, string insertText, bool enabled = true)
		{
			string displayText = node.displayText;
			int num = displayText.IndexOf(insertText);
			if (num != -1 && !enabled)
			{
				node.displayText = displayText.Remove(num, insertText.Length);
			}
			else if (num == -1 && enabled)
			{
				displayText += insertText;
				node.displayText = displayText;
			}
		}

		internal static TerminalNode GetHelpTerminalNode()
		{
			return GetSpecialTerminalNodeByWord("help");
		}

		internal static TerminalNode GetInfoShovelTerminalNode()
		{
			return GetItemInfoTerminalNode("shovel");
		}
	}
	internal static class Tools
	{
		private static Terminal terminal;

		public static void FindCodeInstruction(ref int index, ref List<CodeInstruction> codes, object findValue, MethodInfo addCode, bool skip = false, bool requireInstance = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, string errorMessage = "Not found")
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			bool flag = false;
			while (index < codes.Count)
			{
				if (CheckCodeInstruction(codes[index], findValue))
				{
					flag = true;
					if (!skip)
					{
						if (andInstruction)
						{
							codes.Insert(index + 1, new CodeInstruction(OpCodes.And, (object)null));
						}
						if (!andInstruction && orInstruction)
						{
							codes.Insert(index + 1, new CodeInstruction(OpCodes.Or, (object)null));
						}
						if (notInstruction)
						{
							codes.Insert(index + 1, new CodeInstruction(OpCodes.Not, (object)null));
						}
						codes.Insert(index + 1, new CodeInstruction(OpCodes.Call, (object)addCode));
						if (requireInstance)
						{
							codes.Insert(index + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null));
						}
					}
					break;
				}
				index++;
			}
			if (!flag)
			{
				Plugin.mls.LogError((object)errorMessage);
			}
			index++;
		}

		public static int FindLocalField(int index, ref List<CodeInstruction> codes, int localIndex, object addCode, bool skip = false, bool store = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			bool flag = false;
			while (index < codes.Count)
			{
				if (CheckCodeInstruction(codes[index], localIndex, store))
				{
					flag = true;
					if (!skip)
					{
						codes.Insert(index + 1, new CodeInstruction(OpCodes.Call, addCode));
						if (requireInstance)
						{
							codes.Insert(index + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null));
						}
					}
					break;
				}
				index++;
			}
			if (!flag)
			{
				Plugin.mls.LogError((object)errorMessage);
			}
			return index + 1;
		}

		public static void FindString(ref int index, ref List<CodeInstruction> codes, string findValue, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
		}

		public static void FindField(ref int index, ref List<CodeInstruction> codes, FieldInfo findField, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			FindCodeInstruction(ref index, ref codes, findField, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
		}

		public static void FindMethod(ref int index, ref List<CodeInstruction> codes, MethodInfo findMethod, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			FindCodeInstruction(ref index, ref codes, findMethod, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
		}

		public static void FindFloat(ref int index, ref List<CodeInstruction> codes, float findValue, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
		}

		public static void FindInteger(ref int index, ref List<CodeInstruction> codes, sbyte findValue, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction, andInstruction, orInstruction, errorMessage);
		}

		public static void FindSub(ref int index, ref List<CodeInstruction> codes, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			object findValue = OpCodes.Sub;
			bool notInstruction2 = notInstruction;
			bool andInstruction2 = andInstruction;
			bool orInstruction2 = orInstruction;
			FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction2, andInstruction2, orInstruction2, errorMessage);
		}

		public static void FindDiv(ref int index, ref List<CodeInstruction> codes, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			object findValue = OpCodes.Div;
			bool notInstruction2 = notInstruction;
			bool andInstruction2 = andInstruction;
			bool orInstruction2 = orInstruction;
			FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction2, andInstruction2, orInstruction2, errorMessage);
		}

		public static void FindAdd(ref int index, ref List<CodeInstruction> codes, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			object findValue = OpCodes.Add;
			bool notInstruction2 = notInstruction;
			bool andInstruction2 = andInstruction;
			bool orInstruction2 = orInstruction;
			FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction2, andInstruction2, orInstruction2, errorMessage);
		}

		public static void FindMul(ref int index, ref List<CodeInstruction> codes, MethodInfo addCode = null, bool skip = false, bool notInstruction = false, bool andInstruction = false, bool orInstruction = false, bool requireInstance = false, string errorMessage = "Not found")
		{
			object findValue = OpCodes.Mul;
			bool notInstruction2 = notInstruction;
			bool andInstruction2 = andInstruction;
			bool orInstruction2 = orInstruction;
			FindCodeInstruction(ref index, ref codes, findValue, addCode, skip, requireInstance, notInstruction2, andInstruction2, orInstruction2, errorMessage);
		}

		private static bool CheckCodeInstruction(CodeInstruction code, int localIndex, bool store = false)
		{
			if (!store)
			{
				switch (localIndex)
				{
				case 0:
					return code.opcode == OpCodes.Ldloc_0;
				case 1:
					return code.opcode == OpCodes.Ldloc_1;
				case 2:
					return code.opcode == OpCodes.Ldloc_2;
				case 3:
					return code.opcode == OpCodes.Ldloc_3;
				default:
					if (code.opcode == OpCodes.Ldloc)
					{
						return (int)code.operand == localIndex;
					}
					return false;
				}
			}
			switch (localIndex)
			{
			case 0:
				return code.opcode == OpCodes.Stloc_0;
			case 1:
				return code.opcode == OpCodes.Stloc_1;
			case 2:
				return code.opcode == OpCodes.Stloc_2;
			case 3:
				return code.opcode == OpCodes.Stloc_3;
			default:
				if (code.opcode == OpCodes.Stloc)
				{
					return (int)code.operand == localIndex;
				}
				return false;
			}
		}

		private static bool CheckCodeInstruction(CodeInstruction code, object findValue)
		{
			if (findValue is sbyte)
			{
				return CheckIntegerCodeInstruction(code, findValue);
			}
			if (findValue is float)
			{
				if (code.opcode == OpCodes.Ldc_R4)
				{
					return code.operand.Equals(findValue);
				}
				return false;
			}
			if (findValue is string)
			{
				if (code.opcode == OpCodes.Ldstr)
				{
					return code.operand.Equals(findValue);
				}
				return false;
			}
			if (findValue is MethodInfo)
			{
				if (code.opcode == OpCodes.Call || code.opcode == OpCodes.Callvirt)
				{
					return code.operand == findValue;
				}
				return false;
			}
			if (findValue is FieldInfo)
			{
				if (code.opcode == OpCodes.Ldfld || code.opcode == OpCodes.Stfld)
				{
					return code.operand == findValue;
				}
				return false;
			}
			if (findValue is OpCode)
			{
				return code.opcode == (OpCode)findValue;
			}
			return false;
		}

		private static bool CheckIntegerCodeInstruction(CodeInstruction code, object findValue)
		{
			switch ((sbyte)findValue)
			{
			case 0:
				return code.opcode == OpCodes.Ldc_I4_0;
			case 1:
				return code.opcode == OpCodes.Ldc_I4_1;
			case 2:
				return code.opcode == OpCodes.Ldc_I4_2;
			case 3:
				return code.opcode == OpCodes.Ldc_I4_3;
			case 4:
				return code.opcode == OpCodes.Ldc_I4_4;
			case 5:
				return code.opcode == OpCodes.Ldc_I4_5;
			case 6:
				return code.opcode == OpCodes.Ldc_I4_6;
			case 7:
				return code.opcode == OpCodes.Ldc_I4_7;
			case 8:
				return code.opcode == OpCodes.Ldc_I4_8;
			default:
				if (code.opcode == OpCodes.Ldc_I4_S)
				{
					return code.operand.Equals(findValue);
				}
				return false;
			}
		}

		public static void ShuffleList<T>(List<T> list)
		{
			if (list == null)
			{
				throw new ArgumentNullException("list");
			}
			Random random = new Random();
			int num = list.Count;
			while (num > 1)
			{
				num--;
				int index = random.Next(num + 1);
				T value = list[index];
				list[index] = list[num];
				list[num] = value;
			}
		}

		public static bool SpawnMob(string mob, Vector3 position, int numToSpawn)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < RoundManager.Instance.currentLevel.Enemies.Count; i++)
			{
				if (RoundManager.Instance.currentLevel.Enemies[i].enemyType.enemyName == mob)
				{
					for (int j = 0; j < numToSpawn; j++)
					{
						RoundManager.Instance.SpawnEnemyOnServer(position, 0f, i);
					}
					return true;
				}
			}
			return false;
		}

		internal static string GenerateInfoForUpgrade(string infoFormat, int initialPrice, int[] incrementalPrices, Func<int, float> infoFunction)
		{
			string text = string.Format(infoFormat, 1, initialPrice, infoFunction(0));
			for (int i = 0; i < incrementalPrices.Length; i++)
			{
				float num = infoFunction(i + 1);
				text = ((num % 1f != 0f) ? (text + string.Format(infoFormat, i + 2, incrementalPrices[i], num)) : (text + string.Format(infoFormat, i + 2, incrementalPrices[i], Mathf.RoundToInt(num))));
			}
			return text;
		}

		public static Color ConvertValueToColor(string hex, Color defaultValue)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			Color result = default(Color);
			if (hex == null || !ColorUtility.TryParseHtmlString("#" + hex.Trim('#', ' '), ref result))
			{
				return defaultValue;
			}
			return result;
		}

		internal static string WrapText(string text, int availableLength, string leftPadding = "", string rightPadding = "", bool padLeftFirst = true)
		{
			int num = availableLength - leftPadding.Length - rightPadding.Length;
			string text2 = "";
			string text3 = "";
			int num2 = 0;
			int num3 = -1;
			bool flag = true;
			bool flag2 = false;
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				if (c == '<')
				{
					flag2 = true;
				}
				if (c == ' ' && !flag2)
				{
					num3 = text3.Length;
				}
				if (c != '\n')
				{
					text3 += c;
					if (!flag2)
					{
						num2++;
					}
				}
				if (c == '>' && flag2)
				{
					flag2 = false;
				}
				if (num2 < num && c != '\n')
				{
					continue;
				}
				if (c != '\n' && c != ' ')
				{
					if (num3 != -1)
					{
						string text4 = ((padLeftFirst || !flag) ? leftPadding : "") + text3.Substring(0, num3) + new string(' ', Mathf.Max(0, num - num3)) + rightPadding;
						text2 = text2 + text4 + "\n";
						text3 = text3.Substring(num3 + 1);
					}
					else
					{
						string text5 = ((padLeftFirst || !flag) ? leftPadding : "") + text3 + rightPadding;
						text2 = text2 + text5 + "\n";
						text3 = "";
					}
				}
				else
				{
					if (text3 != "")
					{
						text2 = text2 + ((padLeftFirst || !flag) ? leftPadding : "") + text3 + new string(' ', Mathf.Max(0, num - num2)) + rightPadding + "\n";
					}
					text3 = "";
				}
				num3 = -1;
				flag = false;
				num2 = text3.Length;
			}
			if (text3 != "")
			{
				text2 = text2 + ((padLeftFirst || !flag) ? leftPadding : "") + text3 + new string(' ', Mathf.Max(0, num - num2)) + rightPadding + "\n";
			}
			return text2;
		}

		internal static void SpawnExplosion(Vector3 explosionPosition, bool spawnExplosionEffect = false, float killRange = 1f, float damageRange = 1f, int nonLethalDamage = 50, float physicsForce = 0f, GameObject overridePrefab = null)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Landmine.SpawnExplosion(explosionPosition, spawnExplosionEffect, killRange, damageRange, nonLethalDamage, physicsForce, overridePrefab, false);
		}

		internal static Terminal GetTerminal()
		{
			if ((Object)(object)terminal == (Object)null)
			{
				terminal = GameObject.Find("TerminalScript").GetComponent<Terminal>();
			}
			return terminal;
		}
	}
}
namespace InteractiveTerminalAPI.UI
{
	public class InteractiveTerminalManager : MonoBehaviour
	{
		internal static Dictionary<string, Func<TerminalApplication>> registeredApplications = new Dictionary<string, Func<TerminalApplication>>();

		internal static Dictionary<string, bool> commandSensitive = new Dictionary<string, bool>();

		public static InteractiveTerminalManager Instance;

		internal TerminalApplication mainApplication;

		private Terminal terminalReference;

		private TerminalNode lastTerminalNode;

		private Color previousCaretColor;

		private void Start()
		{
			Instance = this;
			terminalReference = Tools.GetTerminal();
			lastTerminalNode = terminalReference.currentNode;
			UpdateInput(enable: false);
		}

		internal void Initialize(string command)
		{
			Func<TerminalApplication> func = registeredApplications.GetValueOrDefault(command, null);
			if (commandSensitive.ContainsKey(command.ToLower()))
			{
				foreach (string key in registeredApplications.Keys)
				{
					if (string.Equals(key, command, StringComparison.OrdinalIgnoreCase))
					{
						func = registeredApplications[key];
						break;
					}
				}
			}
			if (func == null)
			{
				Plugin.mls.LogError((object)"An application was not selected to change the terminal's text.");
				return;
			}
			mainApplication = func();
			if (mainApplication == null)
			{
				Plugin.mls.LogError((object)"The selected application doesn't have a valid constructor.");
				return;
			}
			mainApplication.Initialization();
			mainApplication.UpdateInputBindings(enable: true);
		}

		private void Update()
		{
			if (!((Object)(object)terminalReference == (Object)null) && mainApplication != null)
			{
				mainApplication.UpdateText();
			}
		}

		private void OnDestroy()
		{
			mainApplication.UpdateInputBindings();
			terminalReference.LoadNewNode(lastTerminalNode);
			((Selectable)terminalReference.screenText).interactable = true;
			terminalReference.screenText.ActivateInputField();
			((Selectable)terminalReference.screenText).Select();
			UpdateInput(enable: true);
			Instance = null;
		}

		internal void UpdateInput(bool enable)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			if (enable)
			{
				((Selectable)terminalReference.screenText).interactable = true;
				terminalReference.screenText.ActivateInputField();
				((Selectable)terminalReference.screenText).Select();
				terminalReference.screenText.caretColor = previousCaretColor;
			}
			else
			{
				terminalReference.screenText.DeactivateInputField(false);
				((Selectable)terminalReference.screenText).interactable = false;
				previousCaretColor = terminalReference.screenText.caretColor;
				terminalReference.screenText.caretColor = APIConstants.Invisible;
			}
		}

		public static bool InteractiveTerminalBeingUsed()
		{
			return (Object)(object)Instance != (Object)null;
		}

		public static bool ContainsApplication(string command)
		{
			if (!commandSensitive.ContainsKey(command.ToLower()))
			{
				return registeredApplications.ContainsKey(command);
			}
			foreach (string key in registeredApplications.Keys)
			{
				if (string.Equals(key, command, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		public static void RegisterApplication<T>(string command) where T : TerminalApplication, new()
		{
			if (registeredApplications.ContainsKey(command))
			{
				Plugin.mls.LogError((object)("An application has already been registered under the command \"" + command + "\""));
				return;
			}
			registeredApplications.Add(command, () => new T());
		}

		public static void RegisterApplication<T>(string command, bool caseSensitive) where T : TerminalApplication, new()
		{
			RegisterApplication<T>(command);
			commandSensitive.Add(command.ToLower(), caseSensitive);
		}

		public static void RegisterApplication<T>(string[] commands) where T : TerminalApplication, new()
		{
			for (int i = 0; i < commands.Length; i++)
			{
				RegisterApplication<T>(commands[i]);
			}
		}

		public static void RegisterApplication<T>(string[] commands, bool caseSensitive) where T : TerminalApplication, new()
		{
			for (int i = 0; i < commands.Length; i++)
			{
				RegisterApplication<T>(commands[i], caseSensitive);
			}
		}
	}
	public interface ITextElement
	{
		string GetText(int availableLength);
	}
	public class TextElement : ITextElement
	{
		public string Text { get; set; }

		public string GetText(int availableLength)
		{
			return Tools.WrapText(Text, availableLength);
		}

		public static TextElement Create(string text = "")
		{
			return new TextElement
			{
				Text = text
			};
		}
	}
}
namespace InteractiveTerminalAPI.UI.Screen
{
	public class BoxedOutputScreen<K, V> : BoxedScreen
	{
		public Func<K> Input { get; set; }

		public Func<K, V> Output { get; set; }

		public V GetOutput()
		{
			if (Output == null || Input == null)
			{
				return default(V);
			}
			return Output(Input());
		}

		public override string GetText(int availableLength)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine().AppendLine();
			stringBuilder.Append(new string(' ', 1)).Append('╔').Append(new string('═', Title.Length + 2))
				.Append('╗')
				.AppendLine();
			stringBuilder.Append('╭').Append('╢').Append(' ')
				.Append(Title)
				.Append(' ')
				.Append('╟')
				.Append(new string('─', availableLength - 6 - Title.Length))
				.Append('╮')
				.AppendLine();
			stringBuilder.Append('│').Append('╚').Append(new string('═', Title.Length + 2))
				.Append('╝')
				.Append(new string(' ', availableLength - 6 - Title.Length))
				.Append('│')
				.AppendLine();
			for (int i = 0; i < elements.Length; i++)
			{
				stringBuilder.Append(Tools.WrapText(elements[i].GetText(availableLength - 4), availableLength, "│ ", " │"));
			}
			string text = GetOutput().ToString();
			int num = availableLength - text.Length - 6;
			stringBuilder.Append('│').Append(new string(' ', num - 3)).Append('╔');
			stringBuilder.Append(new string('═', text.Length + 2)).Append('╗').Append(new string(' ', 3))
				.Append('│')
				.Append('\n');
			stringBuilder.Append('╰').Append(new string('─', num - 3)).Append('╢')
				.Append(' ')
				.Append(text)
				.Append(' ')
				.Append('╟')
				.Append(new string('─', 3))
				.Append('╯')
				.Append('\n');
			stringBuilder.Append(new string(' ', num - 2)).Append('╚').Append(new string('═', text.Length + 2))
				.Append('╝')
				.Append('\n');
			return stringBuilder.ToString();
		}

		public static BoxedOutputScreen<K, V> Create(string title = "", ITextElement[] elements = null, Func<K> input = null, Func<K, V> output = null)
		{
			return new BoxedOutputScreen<K, V>
			{
				Title = title,
				elements = elements,
				Input = input,
				Output = output
			};
		}
	}
	public class BoxedScreen : IScreen, ITextElement
	{
		public string Title;

		public ITextElement[] elements;

		public virtual string GetText(int availableLength)
		{
			string text = Title;
			if (Title.Length > availableLength - 6)
			{
				text = text.Substring(0, availableLength - 6);
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine().AppendLine();
			stringBuilder.Append(new string(' ', 1)).Append('╔').Append(new string('═', text.Length + 2))
				.Append('╗')
				.AppendLine();
			stringBuilder.Append('╭').Append('╢').Append(' ')
				.Append(text)
				.Append(' ')
				.Append('╟')
				.Append(new string('─', availableLength - 6 - text.Length))
				.Append('╮')
				.AppendLine();
			stringBuilder.Append('│').Append('╚').Append(new string('═', text.Length + 2))
				.Append('╝')
				.Append(new string(' ', availableLength - 6 - text.Length))
				.Append('│')
				.AppendLine();
			for (int i = 0; i < elements.Length; i++)
			{
				stringBuilder.Append(Tools.WrapText(elements[i].GetText(availableLength - 4), availableLength, "│ ", " │"));
			}
			stringBuilder.Append('╰').Append(new string('─', availableLength - 2)).Append('╯')
				.AppendLine();
			return stringBuilder.ToString();
		}

		public static BoxedScreen Create(string title = "", ITextElement[] elements = null)
		{
			return new BoxedScreen
			{
				Title = title,
				elements = elements
			};
		}
	}
	public interface IScreen : ITextElement
	{
	}
}
namespace InteractiveTerminalAPI.UI.Page
{
	public class PageCursorElement : PageElement
	{
		public CursorMenu[] cursorMenus;

		public CursorMenu GetCurrentCursorMenu()
		{
			return cursorMenus[pageIndex];
		}

		public void ChangeSorting()
		{
			CollectionExtensions.Do<CursorMenu>((IEnumerable<CursorMenu>)cursorMenus, (Action<CursorMenu>)delegate(CursorMenu x)
			{
				x.ChangeSorting();
			});
			CursorElement[] array = cursorMenus.SelectMany((CursorMenu menu) => menu.elements).ToArray();
			Func<CursorElement, CursorElement, int> sortFunction = cursorMenus[0].GetCurrentSorting();
			Array.Sort(array, (CursorElement x, CursorElement y) => sortFunction(x, y));
			int num = 0;
			CursorMenu[] array2 = cursorMenus;
			foreach (CursorMenu cursorMenu in array2)
			{
				int num2 = cursorMenu.elements.Length;
				Array.Copy(array, num, cursorMenu.elements, 0, num2);
				num += num2;
			}
		}

		public static PageCursorElement Create(int startingPageIndex = 0, IScreen[] elements = null, CursorMenu[] cursorMenus = null)
		{
			return new PageCursorElement
			{
				pageIndex = startingPageIndex,
				elements = elements,
				cursorMenus = cursorMenus
			};
		}
	}
	public class PageElement : ITextElement
	{
		public int pageIndex;

		public IScreen[] elements;

		public string GetText(int availableLength)
		{
			IScreen screen = elements[pageIndex];
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(screen.GetText(availableLength));
			if (elements.Length > 1)
			{
				stringBuilder.Append(new string(' ', availableLength - 30)).Append($"Page {pageIndex + 1}/{elements.Length}");
			}
			return stringBuilder.ToString();
		}

		public void PageUp()
		{
			pageIndex = (pageIndex + 1) % elements.Length;
		}

		public void PageDown()
		{
			pageIndex--;
			if (pageIndex < 0)
			{
				pageIndex = elements.Length - 1;
			}
		}

		public void ResetPage()
		{
			pageIndex = 0;
		}

		public IScreen GetCurrentScreen()
		{
			return elements[pageIndex];
		}

		public static PageElement Create(int startingPageIndex = 0, IScreen[] elements = null)
		{
			return new PageElement
			{
				pageIndex = startingPageIndex,
				elements = elements
			};
		}
	}
}
namespace InteractiveTerminalAPI.UI.Hierarchy
{
	public class BaseCursorHierarchyElement : CursorElement
	{
		private CursorMenu previousCursorMenu;

		public char IntersectionCharacter { get; set; } = '├';


		public char LastIntersectionCharacter { get; set; } = '└';


		public char SpacingCharacter { get; set; } = '─';


		public int Spacing { get; set; } = 2;


		public char VerticalSpacingCharacter { get; set; } = '│';


		public int VerticalSpacing { get; set; } = 1;


		public string Title { get; set; }

		public CursorMenu innerCursorMenu { get; set; }

		public bool Selected { get; set; }

		public override void ExecuteAction()
		{
			base.ExecuteAction();
			Selected = true;
			if (InteractiveTerminalManager.Instance.mainApplication is InteractiveTerminalApplication interactiveTerminalApplication)
			{
				Keybinds.cursorExitAction.performed -= InteractiveTerminalManager.Instance.mainApplication.OnScreenExit;
				Keybinds.cursorExitAction.performed += OnHierarchyExit;
				previousCursorMenu = interactiveTerminalApplication.currentCursorMenu;
				interactiveTerminalApplication.currentCursorMenu = innerCursorMenu;
			}
		}

		public void OnHierarchyExit(CallbackContext context)
		{
			Keybinds.cursorExitAction.performed += InteractiveTerminalManager.Instance.mainApplication.OnScreenExit;
			Keybinds.cursorExitAction.performed -= OnHierarchyExit;
			if (InteractiveTerminalManager.Instance.mainApplication is InteractiveTerminalApplication interactiveTerminalApplication)
			{
				interactiveTerminalApplication.currentCursorMenu = previousCursorMenu;
				previousCursorMenu = null;
			}
			Selected = false;
		}

		public override string GetText(int availableLength)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(Title);
			if (!Selected)
			{
				return stringBuilder.ToString();
			}
			stringBuilder.Append("\n");
			int num = 0;
			CursorElement[] elements = innerCursorMenu.elements;
			int num2 = 0;
			while (num2 < elements.Length)
			{
				CursorElement cursorElement = elements[num2];
				if (num != VerticalSpacing)
				{
					stringBuilder.Append(VerticalSpacingCharacter + "\n");
					num++;
					continue;
				}
				num = 0;
				bool flag = num2 == elements.Length - 1;
				if (flag)
				{
					stringBuilder.Append(LastIntersectionCharacter);
				}
				else
				{
					stringBuilder.Append(IntersectionCharacter);
				}
				stringBuilder.Append(new string(SpacingCharacter, Spacing));
				stringBuilder.Append(' ');
				string text = cursorElement.GetText(availableLength - 5 - Spacing);
				string arg = (cursorElement.Active(cursorElement) ? "#00FF0066" : "#66666633");
				text = ((num2 == innerCursorMenu.cursorIndex) ? string.Format("<mark={0}><color={1}>{2}</color></mark>", arg, "#FFFFFFFF", text) : text);
				if (cursorElement is BaseCursorHierarchyElement)
				{
					stringBuilder.Append(Tools.WrapText(text, availableLength - 5 - Spacing, ((!flag) ? new string(VerticalSpacingCharacter, 1) : "") + new string(' ', Spacing + 1), "", padLeftFirst: false));
				}
				else if (flag)
				{
					stringBuilder.Append(Tools.WrapText(text, availableLength - 5 - Spacing));
				}
				else
				{
					stringBuilder.Append(Tools.WrapText(text, availableLength - 5 - Spacing, new string(VerticalSpacingCharacter, 1), "", padLeftFirst: false));
				}
				num2++;
			}
			return stringBuilder.ToString();
		}
	}
	public abstract class BaseHierarchyElement<T> : ITextElement where T : ITextElement
	{
		public char IntersectionCharacter { get; set; } = '├';


		public char LastIntersectionCharacter { get; set; } = '└';


		public char SpacingCharacter { get; set; } = '─';


		public int Spacing { get; set; } = 2;


		public char VerticalSpacingCharacter { get; set; } = '│';


		public int VerticalSpacing { get; set; } = 1;


		public string Title { get; set; }

		public T[] textElements { get; set; }

		public string GetText(int availableLength)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(Title + "\n");
			int num = 0;
			int num2 = 0;
			while (num2 < textElements.Length)
			{
				T val = textElements[num2];
				if (num != VerticalSpacing)
				{
					stringBuilder.Append(VerticalSpacingCharacter + "\n");
					num++;
					continue;
				}
				num = 0;
				bool flag = num2 == textElements.Length - 1;
				if (flag)
				{
					stringBuilder.Append(LastIntersectionCharacter);
				}
				else
				{
					stringBuilder.Append(IntersectionCharacter);
				}
				stringBuilder.Append(new string(SpacingCharacter, Spacing));
				stringBuilder.Append(' ');
				T val2;
				if (val is BaseHierarchyElement<T>)
				{
					ref T reference = ref val;
					val2 = default(T);
					if (val2 == null)
					{
						val2 = reference;
						reference = ref val2;
					}
					stringBuilder.Append(Tools.WrapText(reference.GetText(availableLength - 5 - Spacing), availableLength - 5 - Spacing, ((!flag) ? new string(VerticalSpacingCharacter, 1) : "") + new string(' ', Spacing + 1), "", padLeftFirst: false));
				}
				else if (flag)
				{
					ref T reference2 = ref val;
					val2 = default(T);
					if (val2 == null)
					{
						val2 = reference2;
						reference2 = ref val2;
					}
					stringBuilder.Append(Tools.WrapText(reference2.GetText(availableLength - 5 - Spacing), availableLength - 5 - Spacing));
				}
				else
				{
					ref T reference3 = ref val;
					val2 = default(T);
					if (val2 == null)
					{
						val2 = reference3;
						reference3 = ref val2;
					}
					stringBuilder.Append(Tools.WrapText(reference3.GetText(availableLength - 5 - Spacing), availableLength - 5 - Spacing, new string(VerticalSpacingCharacter, 1), "", padLeftFirst: false));
				}
				num2++;
			}
			return stringBuilder.ToString();
		}
	}
	internal class TextHierarchyElement : BaseHierarchyElement<ITextElement>
	{
		public static TextHierarchyElement Create(string title, ITextElement[] textElements, int spacing = 2, char intersectionCharacter = '├', char lastIntersectionCharacter = '└', char spacingCharacter = '─')
		{
			return new TextHierarchyElement
			{
				Title = title,
				textElements = textElements,
				Spacing = spacing,
				IntersectionCharacter = intersectionCharacter,
				LastIntersectionCharacter = lastIntersectionCharacter,
				SpacingCharacter = spacingCharacter
			};
		}
	}
}
namespace InteractiveTerminalAPI.UI.Cursor
{
	public abstract class BaseCursorCounterMenu<T> : BaseCursorMenu<T> where T : CursorCounterElement
	{
		public void IncrementCounter()
		{
			elements[cursorIndex].IncrementCounter();
		}

		public void DecrementCounter()
		{
			elements[cursorIndex].DecrementCounter();
		}
	}
	public abstract class BaseCursorMenu<T> : ITextElement where T : CursorElement
	{
		public char cursorCharacter = '>';

		public int cursorIndex;

		public int sortingIndex;

		public T[] elements;

		public Func<T, T, int>[] SortingFunctions { get; set; }

		public void Execute()
		{
			elements[cursorIndex].ExecuteAction();
		}

		public Func<T, T, int> GetCurrentSorting()
		{
			return SortingFunctions[sortingIndex];
		}

		public void ChangeSorting()
		{
			sortingIndex = (sortingIndex + 1) % SortingFunctions.Length;
			Array.Sort(elements, (T x, T y) => SortingFunctions[sortingIndex](x, y));
		}

		public void Forward()
		{
			cursorIndex = (cursorIndex + 1) % elements.Length;
			while (elements[cursorIndex] == null || (!elements[cursorIndex].Active(elements[cursorIndex]) && !elements[cursorIndex].SelectInactive))
			{
				cursorIndex = (cursorIndex + 1) % elements.Length;
			}
		}

		public void Backward()
		{
			cursorIndex--;
			if (cursorIndex < 0)
			{
				cursorIndex = elements.Length - 1;
			}
			while (elements[cursorIndex] == null || (!elements[cursorIndex].Active(elements[cursorIndex]) && !elements[cursorIndex].SelectInactive))
			{
				cursorIndex--;
				if (cursorIndex < 0)
				{
					cursorIndex = elements.Length - 1;
				}
			}
		}

		public void ResetCursor()
		{
			cursorIndex = 0;
		}

		public abstract string GetText(int availableLength);
	}
	public class CursorCounterElement : CursorElement
	{
		public int Counter { get; set; }

		public bool ShowCounter { get; set; }

		public void ToggleShow(bool showCounter)
		{
			ShowCounter = showCounter;
		}

		public void IncrementCounter()
		{
			Counter++;
		}

		public void DecrementCounter()
		{
			if (Counter > 0)
			{
				Counter--;
			}
		}

		public override string GetText(int availableLength)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (!base.Active(this))
			{
				stringBuilder.Append(string.Format("<color={0}>", "#666666"));
			}
			if (ShowCounter)
			{
				stringBuilder.Append('←').Append(Counter).Append('→')
					.Append(' ');
			}
			stringBuilder.Append(base.GetText(availableLength));
			if (!base.Active(this))
			{
				stringBuilder.Append("</color>");
			}
			return stringBuilder.ToString();
		}

		public static CursorCounterElement Create(string name = "", string description = "", Action action = null, int counter = 0, Func<CursorElement, bool> active = null, bool selectInactive = true, bool showCounter = true)
		{
			return new CursorCounterElement
			{
				Name = name,
				Description = description,
				Action = action,
				Counter = counter,
				Active = ((active == null) ? ((Func<CursorElement, bool>)((CursorElement _) => true)) : active),
				SelectInactive = selectInactive,
				ShowCounter = showCounter
			};
		}
	}
	public class CursorCounterMenu : BaseCursorCounterMenu<CursorCounterElement>
	{
		public override string GetText(int availableLength)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < elements.Length; i++)
			{
				CursorCounterElement cursorCounterElement = elements[i];
				if (cursorCounterElement != null)
				{
					if (i == cursorIndex)
					{
						stringBuilder.Append(cursorCharacter).Append(' ');
					}
					else
					{
						stringBuilder.Append(' ').Append(' ');
					}
					string text = cursorCounterElement.GetText(availableLength - 2);
					string arg = (cursorCounterElement.Active(cursorCounterElement) ? "#00FF0066" : "#66666633");
					text = ((i == cursorIndex) ? string.Format("<mark={0}><color={1}>{2}</color></mark>", arg, "#FFFFFFFF", text) : text);
					stringBuilder.Append(Tools.WrapText(text, availableLength, "  ", "", padLeftFirst: false));
				}
			}
			return stringBuilder.ToString();
		}

		public static CursorCounterMenu Create<T>(int startingCursorIndex = 0, char cursorCharacter = '>', T[] elements = null, Func<CursorElement, CursorElement, int>[] sorting = null) where T : CursorCounterElement
		{
			if (sorting == null)
			{
				sorting = new Func<CursorElement, CursorElement, int>[1]
				{
					(CursorElement element1, CursorElement element2) => string.Compare(element2.Name, element1.Name)
				};
			}
			CursorCounterMenu obj = new CursorCounterMenu
			{
				cursorIndex = startingCursorIndex,
				cursorCharacter = cursorCharacter
			};
			obj.elements = elements;
			Func<CursorCounterElement, CursorCounterElement, int>[] sortingFunctions = sorting;
			obj.SortingFunctions = sortingFunctions;
			return obj;
		}
	}
	public class CursorElement : ITextElement
	{
		public string Name { get; set; }

		public string Description { get; set; }

		public Func<CursorElement, bool> Active { get; set; } = (CursorElement x) => true;


		public bool SelectInactive { get; set; } = true;


		public Action Action { get; set; }

		public virtual string GetText(int availableLength)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (!Active(this))
			{
				stringBuilder.Append(string.Format("<color={0}>", "#666666"));
			}
			stringBuilder.Append(Name);
			if (!Active(this))
			{
				stringBuilder.Append("</color>");
			}
			if (!string.IsNullOrEmpty(Description))
			{
				stringBuilder.Append("\n" + Tools.WrapText(Description, availableLength));
			}
			return stringBuilder.ToString();
		}

		public virtual void ExecuteAction()
		{
			if (Action != null)
			{
				Action();
			}
		}

		public static CursorElement Create(string name = "", string description = "", Action action = null, Func<CursorElement, bool> active = null, bool selectInactive = true)
		{
			return new CursorElement
			{
				Name = name,
				Description = description,
				Action = action,
				Active = ((active == null) ? ((Func<CursorElement, bool>)((CursorElement _) => true)) : active),
				SelectInactive = selectInactive
			};
		}
	}
	public class CursorMenu : BaseCursorMenu<CursorElement>
	{
		public override string GetText(int availableLength)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < elements.Length; i++)
			{
				CursorElement cursorElement = elements[i];
				if (cursorElement != null)
				{
					if (i == cursorIndex)
					{
						stringBuilder.Append(cursorCharacter).Append(' ');
					}
					else
					{
						stringBuilder.Append(' ').Append(' ');
					}
					string text = cursorElement.GetText(availableLength - 2);
					string arg = (cursorElement.Active(cursorElement) ? "#00FF0066" : "#66666633");
					if (!(cursorElement is BaseCursorHierarchyElement baseCursorHierarchyElement) || !baseCursorHierarchyElement.Selected)
					{
						text = ((i == cursorIndex) ? string.Format("<mark={0}><color={1}>{2}</color></mark>", arg, "#FFFFFFFF", text) : text);
					}
					stringBuilder.Append(Tools.WrapText(text, availableLength, "  ", "", padLeftFirst: false));
				}
			}
			return stringBuilder.ToString();
		}

		public static CursorMenu Create(int startingCursorIndex = 0, char cursorCharacter = '>', CursorElement[] elements = null, Func<CursorElement, CursorElement, int>[] sorting = null)
		{
			if (sorting == null)
			{
				sorting = new Func<CursorElement, CursorElement, int>[1]
				{
					(CursorElement element1, CursorElement element2) => string.Compare(element2.Name, element1.Name)
				};
			}
			return new CursorMenu
			{
				cursorIndex = startingCursorIndex,
				cursorCharacter = cursorCharacter,
				elements = elements,
				SortingFunctions = sorting
			};
		}
	}
	public class CursorOutputElement<T> : CursorCounterElement
	{
		public Func<int, T> Func { get; set; }

		public T ApplyFunction()
		{
			return Func(base.Counter);
		}

		public override string GetText(int availableLength)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (!base.Active(this))
			{
				stringBuilder.Append(string.Format("<color={0}>", "#666666"));
			}
			stringBuilder.Append(base.GetText(availableLength));
			stringBuilder.Append(new string(' ', 10));
			stringBuilder.Append(ApplyFunction());
			if (!base.Active(this))
			{
				stringBuilder.Append("</color>");
			}
			return stringBuilder.ToString();
		}

		public static CursorOutputElement<T> Create(string name = "", string description = "", Action action = null, int counter = 0, Func<int, T> func = null, Func<CursorElement, bool> active = null, bool selectInactive = true, bool showCounter = true)
		{
			return new CursorOutputElement<T>
			{
				Name = name,
				Description = description,
				Action = action,
				Counter = counter,
				Func = func,
				Active = ((active == null) ? ((Func<CursorElement, bool>)((CursorElement _) => true)) : active),
				SelectInactive = selectInactive,
				ShowCounter = showCounter
			};
		}
	}
}
namespace InteractiveTerminalAPI.UI.Application
{
	public abstract class BaseInteractiveApplication<K, V> : TerminalApplication where K : BaseCursorMenu<V> where V : CursorElement
	{
		public K currentCursorMenu;

		public K previousCursorMenu;

		public IScreen previousScreen;

		protected override string GetApplicationText()
		{
			return currentScreen.GetText(51);
		}

		protected override Action PreviousScreen()
		{
			return delegate
			{
				SwitchScreen((previousScreen != null) ? previousScreen : currentScreen, (previousCursorMenu != null) ? previousCursorMenu : currentCursorMenu, previous: true);
			};
		}

		protected override void AddInputBindings()
		{
			base.AddInputBindings();
			Keybinds.changeSortingAction.performed += OnApplicationChangeSorting;
			Keybinds.cursorUpAction.performed += OnApplicationCursorUp;
			Keybinds.cursorDownAction.performed += OnApplicationCursorDown;
			Keybinds.storeConfirmAction.performed += OnApplicationConfirm;
		}

		protected override void RemoveInputBindings()
		{
			base.RemoveInputBindings();
			Keybinds.changeSortingAction.performed -= OnApplicationChangeSorting;
			Keybinds.cursorUpAction.performed -= OnApplicationCursorUp;
			Keybinds.cursorDownAction.performed -= OnApplicationCursorDown;
			Keybinds.storeConfirmAction.performed -= OnApplicationConfirm;
		}

		internal void OnApplicationConfirm(CallbackContext context)
		{
			Submit();
		}

		internal void OnApplicationCursorUp(CallbackContext context)
		{
			MoveCursorUp();
		}

		internal void OnApplicationChangeSorting(CallbackContext context)
		{
			ChangeSorting();
		}

		internal void OnApplicationCursorDown(CallbackContext context)
		{
			MoveCursorDown();
		}

		protected virtual void ChangeSorting()
		{
			currentCursorMenu.ChangeSorting();
		}

		public virtual void MoveCursorUp()
		{
			currentCursorMenu.Backward();
		}

		public virtual void MoveCursorDown()
		{
			currentCursorMenu.Forward();
		}

		public void Submit()
		{
			currentCursorMenu.Execute();
		}

		protected virtual void SwitchScreen(IScreen screen, K cursorMenu, bool previous)
		{
			previousScreen = screen;
			previousCursorMenu = currentCursorMenu;
			currentScreen = screen;
			currentCursorMenu = cursorMenu;
			if (!previous)
			{
				cursorMenu.cursorIndex = 0;
			}
		}
	}
	public abstract class InteractiveCounterApplication<K, V> : BaseInteractiveApplication<K, V> where K : BaseCursorCounterMenu<V> where V : CursorCounterElement
	{
		protected override void AddInputBindings()
		{
			base.AddInputBindings();
			Keybinds.pageUpAction.performed += OnApplicationCountUp;
			Keybinds.pageDownAction.performed += OnApplicationCountDown;
		}

		protected override void RemoveInputBindings()
		{
			base.RemoveInputBindings();
			Keybinds.pageUpAction.performed -= OnApplicationCountUp;
			Keybinds.pageDownAction.performed -= OnApplicationCountDown;
		}

		private void IncrementSelectedCounter()
		{
			currentCursorMenu.IncrementCounter();
		}

		private void DecrementSelectedCounter()
		{
			currentCursorMenu.DecrementCounter();
		}

		internal void OnApplicationCountUp(CallbackContext context)
		{
			IncrementSelectedCounter();
		}

		internal void OnApplicationCountDown(CallbackContext context)
		{
			DecrementSelectedCounter();
		}
	}
	public abstract class InteractiveTerminalApplication : BaseInteractiveApplication<CursorMenu, CursorElement>
	{
		protected void Confirm(string title, string description, Action confirmAction, Action declineAction, string additionalMessage = "")
		{
			CursorElement[] elements = new CursorElement[2]
			{
				CursorElement.Create("Confirm", "", confirmAction),
				CursorElement.Create("Abort", "", declineAction)
			};
			CursorMenu cursorMenu = CursorMenu.Create(0, '>', elements);
			ITextElement[] elements2 = new ITextElement[4]
			{
				TextElement.Create(description),
				TextElement.Create(" "),
				TextElement.Create(additionalMessage),
				cursorMenu
			};
			IScreen screen = BoxedScreen.Create(title, elements2);
			SwitchScreen(screen, cursorMenu, previous: false);
		}

		protected void ErrorMessage(string title, Action backAction, string error)
		{
			CursorElement[] elements = new CursorElement[1] { CursorElement.Create("Back", "", backAction) };
			CursorMenu cursorMenu = CursorMenu.Create(0, '>', elements);
			ITextElement[] elements2 = new ITextElement[3]
			{
				TextElement.Create(error),
				TextElement.Create(" "),
				cursorMenu
			};
			IScreen screen = BoxedScreen.Create(title, elements2);
			SwitchScreen(screen, cursorMenu, previous: false);
		}

		protected void ErrorMessage(string title, string description, Action backAction, string error)
		{
			CursorElement[] elements = new CursorElement[1] { CursorElement.Create("Back", "", backAction) };
			CursorMenu cursorMenu = CursorMenu.Create(0, '>', elements);
			ITextElement[] elements2 = new ITextElement[5]
			{
				TextElement.Create(description),
				TextElement.Create(" "),
				TextElement.Create(error),
				TextElement.Create(" "),
				cursorMenu
			};
			IScreen screen = BoxedScreen.Create(title, elements2);
			SwitchScreen(screen, cursorMenu, previous: false);
		}
	}
	public abstract class PageApplication : InteractiveTerminalApplication
	{
		protected PageCursorElement initialPage;

		protected PageCursorElement previousPage;

		protected PageCursorElement currentPage;

		protected override string GetApplicationText()
		{
			if (currentScreen != currentPage.GetCurrentScreen())
			{
				return currentScreen.GetText(51);
			}
			return currentPage.GetText(51);
		}

		protected virtual int GetEntriesPerPage<T>(T[] entries)
		{
			return Mathf.CeilToInt((float)entries.Length / 2f);
		}

		protected override Action PreviousScreen()
		{
			return delegate
			{
				if (previousPage != null)
				{
					SwitchScreen(previousPage, previous: true);
				}
				else
				{
					ResetScreen();
				}
			};
		}

		protected virtual int GetAmountPages<T>(T[] entries)
		{
			return Mathf.CeilToInt((float)entries.Length / (float)GetEntriesPerPage(entries));
		}

		protected override void ChangeSorting()
		{
			currentPage.ChangeSorting();
		}

		public override void MoveCursorUp()
		{
			int cursorIndex = currentCursorMenu.cursorIndex;
			base.MoveCursorUp();
			if (currentPage.GetCurrentCursorMenu() == currentCursorMenu && currentCursorMenu.cursorIndex > cursorIndex)
			{
				ChangeScreenBackward();
				base.MoveCursorUp();
			}
		}

		public override void MoveCursorDown()
		{
			int cursorIndex = currentCursorMenu.cursorIndex;
			base.MoveCursorDown();
			if (currentPage.GetCurrentCursorMenu() == currentCursorMenu && currentCursorMenu.cursorIndex < cursorIndex)
			{
				ChangeScreenForward();
				currentCursorMenu.cursorIndex = 0;
			}
		}

		protected void ResetScreen()
		{
			SwitchScreen(initialPage, previous: true);
		}

		protected void SwitchScreen(PageCursorElement pages, bool previous)
		{
			previousPage = currentPage;
			currentPage = pages;
			SwitchScreen(currentPage.GetCurrentScreen(), currentPage.GetCurrentCursorMenu(), previous);
		}

		protected override void SwitchScreen(IScreen screen, CursorMenu cursorMenu, bool previous)
		{
			base.SwitchScreen(screen, cursorMenu, previous);
			if (screen == currentPage.GetCurrentScreen())
			{
				Keybinds.pageUpAction.performed += OnApplicationPageUp;
				Keybinds.pageDownAction.performed += OnApplicationPageDown;
			}
			else
			{
				Keybinds.pageUpAction.performed -= OnApplicationPageUp;
				Keybinds.pageDownAction.performed -= OnApplicationPageDown;
			}
		}

		public void ChangeScreenForward()
		{
			currentPage.PageUp();
			SwitchScreen(currentPage.GetCurrentScreen(), currentPage.GetCurrentCursorMenu(), previous: false);
		}

		public void ChangeScreenBackward()
		{
			currentPage.PageDown();
			SwitchScreen(currentPage.GetCurrentScreen(), currentPage.GetCurrentCursorMenu(), previous: false);
		}

		protected override void AddInputBindings()
		{
			base.AddInputBindings();
			Keybinds.pageUpAction.performed += OnApplicationPageUp;
			Keybinds.pageDownAction.performed += OnApplicationPageDown;
		}

		protected override void RemoveInputBindings()
		{
			base.RemoveInputBindings();
			Keybinds.pageUpAction.performed -= OnApplicationPageUp;
			Keybinds.pageDownAction.performed -= OnApplicationPageDown;
		}

		protected (T[][], CursorMenu[], IScreen[]) GetPageEntries<T>(T[] entries)
		{
			int amountPages = GetAmountPages(entries);
			int entriesPerPage = GetEntriesPerPage(entries);
			T[][] array = new T[amountPages][];
			for (int i = 0; i < amountPages; i++)
			{
				array[i] = new T[entriesPerPage];
			}
			for (int j = 0; j < entries.Length; j++)
			{
				int num = j / entriesPerPage;
				int num2 = j % entriesPerPage;
				array[num][num2] = entries[j];
			}
			CursorMenu[] array2 = new CursorMenu[array.Length];
			IScreen[] array3 = new IScreen[array.Length];
			CursorMenu[] cursorMenus = array2;
			initialPage = PageCursorElement.Create(0, array3, cursorMenus);
			return (array, array2, array3);
		}

		internal void OnApplicationPageUp(CallbackContext context)
		{
			ChangeScreenForward();
		}

		internal void OnApplicationPageDown(CallbackContext context)
		{
			ChangeScreenBackward();
		}
	}
	public abstract class TerminalApplication
	{
		protected IScreen currentScreen;

		protected readonly Terminal terminal = Tools.GetTerminal();

		public abstract void Initialization();

		protected abstract string GetApplicationText();

		protected abstract Action PreviousScreen();

		public void UpdateText()
		{
			string applicationText = GetApplicationText();
			terminal.screenText.text = applicationText;
			terminal.currentText = applicationText;
		}

		internal void UpdateInputBindings(bool enable = false)
		{
			if (enable)
			{
				AddInputBindings();
			}
			else
			{
				RemoveInputBindings();
			}
		}

		protected virtual void AddInputBindings()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Keybinds.cursorExitAction.performed += OnScreenExit;
			MovementActions movement = terminal.playerActions.Movement;
			((MovementActions)(ref movement)).OpenMenu.performed -= terminal.PressESC;
		}

		protected virtual void RemoveInputBindings()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Keybinds.cursorExitAction.performed -= OnScreenExit;
			MovementActions movement = terminal.playerActions.Movement;
			((MovementActions)(ref movement)).OpenMenu.performed += terminal.PressESC;
		}

		public void OnScreenExit(CallbackContext context)
		{
			Object.Destroy((Object)(object)InteractiveTerminalManager.Instance);
		}
	}
}
namespace InteractiveTerminalAPI.Patches.TerminalComponents
{
	[HarmonyPatch(typeof(Terminal))]
	internal static class TerminalPatcher
	{
		[HarmonyTranspiler]
		[HarmonyPatch("Update")]
		private static IEnumerable<CodeInstruction> UpdateTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo method = typeof(InteractiveTerminalManager).GetMethod("InteractiveTerminalBeingUsed");
			MethodInfo method2 = typeof(ButtonControl).GetMethod("get_wasPressedThisFrame");
			List<CodeInstruction> codes = new List<CodeInstruction>(instructions);
			int index = 0;
			Tools.FindMethod(ref index, ref codes, method2, method, skip: false, notInstruction: true, andInstruction: true, orInstruction: false, requireInstance: false, "Couldn't find field used to check if the terminal is being used");
			return codes;
		}

		[HarmonyPostfix]
		[HarmonyPatch("ParsePlayerSentence")]
		private static void CustomParser(ref Terminal __instance, ref TerminalNode __result)
		{
			string command = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded);
			if (InteractiveTerminalManager.ContainsApplication(command))
			{
				GameObject obj = Object.Instantiate<GameObject>(GameObject.CreatePrimitive((PrimitiveType)3));
				((Object)obj).name = "InteractiveTerminal";
				Object.Destroy((Object)(object)obj.GetComponent<MeshRenderer>());
				Object.Destroy((Object)(object)obj.GetComponent<MeshFilter>());
				Object.Destroy((Object)(object)obj.GetComponent<BoxCollider>());
				obj.AddComponent<InteractiveTerminalManager>().Initialize(command);
				__result = TerminalNodeUtils.GetHelpTerminalNode();
			}
		}
	}
}
namespace InteractiveTerminalAPI.Misc
{
	internal static class Metadata
	{
		public const string GUID = "WhiteSpike.InteractiveTerminalAPI";

		public const string NAME = "Interactive Terminal API";

		public const string VERSION = "1.2.0";
	}
}
namespace InteractiveTerminalAPI.Misc.Util
{
	internal static class APIConstants
	{
		internal const char WHITE_SPACE = ' ';

		internal const string HEXADECIMAL_RED = "#FF0000";

		internal const string HEXADECIMAL_WHITE = "#FFFFFF";

		internal const string HEXADECIMAL_GREEN = "#00FF00";

		internal const string HEXADECIMAL_GREY = "#666666";

		internal const string MOVE_CURSOR_UP_KEYBIND_NAME = "Move Cursor Up in the current application";

		internal const string MOVE_CURSOR_UP_DEFAULT_KEYBIND = "<Keyboard>/w";

		internal const string MOVE_CURSOR_DOWN_KEYBIND_NAME = "Move Cursor Down in the current application";

		internal const string MOVE_CURSOR_DOWN_DEFAULT_KEYBIND = "<Keyboard>/s";

		internal const string EXIT_STORE_KEYBIND_NAME = "Exit application";

		internal const string EXIT_STORE_DEFAULT_KEYBIND = "<Keyboard>/escape";

		internal const string NEXT_PAGE_KEYBIND_NAME = "Next Page in the current application";

		internal const string NEXT_PAGE_DEFAULT_KEYBIND = "<Keyboard>/d";

		internal const string PREVIOUS_PAGE_KEYBIND_NAME = "Previous Page in the current application";

		internal const string PREVIOUS_PAGE_DEFAULT_KEYBIND = "<Keyboard>/a";

		internal const string SUBMIT_PROMPT_KEYBIND_NAME = "Submit Prompt in the current application";

		internal const string SUBMIT_PROMPT_DEFAULT_KEYBIND = "<Keyboard>/enter";

		internal const string CHANGE_SORTING_KEYBIND_NAME = "Change sorting in the current application";

		internal const string CHANGE_SORTING_DEFAULT_KEYBIND = "<Keyboard>/f";

		internal const char INTERSECTION = '├';

		internal const char LAST_INTERSECTION = '└';

		internal const char SPACING = '─';

		internal const int SPACING_AMOUNT = 2;

		internal const char VERTICAL_SPACING = '│';

		internal const int VERTICAL_SPACING_AMOUNT = 1;

		internal const char CURSOR = '>';

		internal const string SELECTED_CURSOR_ELEMENT_FORMAT = "<mark={0}><color={1}>{2}</color></mark>";

		internal const string COLOR_INITIAL_FORMAT = "<color={0}>";

		internal const string COLOR_FINAL_FORMAT = "</color>";

		internal const string DEFAULT_BACKGROUND_SELECTED_COLOR = "#00FF0066";

		internal const string INACTIVE_BACKGROUND_SELECTED_COLOR = "#66666633";

		internal const string DEFAULT_TEXT_SELECTED_COLOR = "#FFFFFFFF";

		internal const string DEFAULT_DEACTIVATED_TEXT_COLOUR = "#66666655";

		internal const string GO_BACK_PROMPT = "Back";

		internal const string CONFIRM_PROMPT = "Confirm";

		internal const string CANCEL_PROMPT = "Abort";

		internal const int AVAILABLE_CHARACTERS_PER_LINE = 51;

		internal const char TOP_LEFT_CORNER = '╭';

		internal const char TOP_RIGHT_CORNER = '╮';

		internal const char BOTTOM_LEFT_CORNER = '╰';

		internal const char BOTTOM_RIGHT_CORNER = '╯';

		internal const char VERTICAL_LINE = '│';

		internal const char HORIZONTAL_LINE = '─';

		internal const char CONNECTING_TITLE_LEFT = '╢';

		internal const char CONNECTING_TITLE_RIGHT = '╟';

		internal const char TOP_RIGHT_TITLE_CORNER = '╗';

		internal const char TOP_LEFT_TITLE_CORNER = '╔';

		internal const char BOTTOM_RIGHT_TITLE_CORNER = '╝';

		internal const char BOTTOM_LEFT_TITLE_CORNER = '╚';

		internal const char VERTICAL_TITLE_LINE = '║';

		internal const char HORIZONTAL_TITLE_LINE = '═';

		internal const char LEFT_ARROW = '←';

		internal const char RIGHT_ARROW = '→';

		internal const int START_PAGE_COUNTER = 30;

		internal const int NAME_LENGTH = 17;

		internal const int LEVEL_LENGTH = 7;

		internal const char EMPTY_LEVEL = '○';

		internal const char FILLED_LEVEL = '●';

		internal static readonly Color Invisible = new Color(0f, 0f, 0f, 0f);
	}
}
namespace InteractiveTerminalAPI.Input
{
	internal class IngameKeybinds : LcInputActions
	{
		public static IngameKeybinds Instance;

		[InputAction("<Keyboard>/w", Name = "Move Cursor Up in the current application")]
		public InputAction UpgradeStoreCursorUpKey { get; set; }

		[InputAction("<Keyboard>/s", Name = "Move Cursor Down in the current application")]
		public InputAction UpgradeStoreCursorDownKey { get; set; }

		[InputAction("<Keyboard>/escape", Name = "Exit application")]
		public InputAction UpgradeStoreCursorExitKey { get; set; }

		[InputAction("<Keyboard>/d", Name = "Next Page in the current application")]
		public InputAction UpgradeStorePageUpKey { get; set; }

		[InputAction("<Keyboard>/a", Name = "Previous Page in the current application")]
		public InputAction UpgradeStorePageDownKey { get; set; }

		[InputAction("<Keyboard>/enter", Name = "Submit Prompt in the current application")]
		public InputAction LguStoreConfirmKey { get; set; }

		[InputAction("<Keyboard>/f", Name = "Change sorting in the current application")]
		public InputAction ApplicationChangeSorting { get; set; }

		internal static InputActionAsset GetAsset()
		{
			return ((LcInputActions)Instance).Asset;
		}
	}
	[HarmonyPatch]
	internal static class Keybinds
	{
		public static InputActionAsset Asset;

		public static InputActionMap ActionMap;

		public static InputAction cursorUpAction;

		public static InputAction cursorDownAction;

		public static InputAction cursorExitAction;

		public static InputAction pageUpAction;

		public static InputAction pageDownAction;

		public static InputAction storeConfirmAction;

		public static InputAction changeSortingAction;

		public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController;

		[HarmonyPatch(typeof(PreInitSceneScript), "Awake")]
		[HarmonyPrefix]
		public static void AddToKeybindMenu()
		{
			//IL_000f: 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)
			Asset = InputUtils_Compat.Asset;
			ActionMap = Asset.actionMaps[0];
			cursorUpAction = InputUtils_Compat.CursorUpKey;
			cursorDownAction = InputUtils_Compat.CursorDownKey;
			cursorExitAction = InputUtils_Compat.CursorExitKey;
			pageUpAction = InputUtils_Compat.PageUpKey;
			pageDownAction = InputUtils_Compat.PageDownKey;
			storeConfirmAction = InputUtils_Compat.LguStoreConfirmKey;
			changeSortingAction = InputUtils_Compat.ChangeApplicationSortingKey;
		}
	}
}
namespace InteractiveTerminalAPI.Compat
{
	public static class InputUtils_Compat
	{
		internal static InputActionAsset Asset => IngameKeybinds.GetAsset();

		public static InputAction CursorUpKey => IngameKeybinds.Instance.UpgradeStoreCursorUpKey;

		public static InputAction CursorDownKey => IngameKeybinds.Instance.UpgradeStoreCursorDownKey;

		public static InputAction CursorExitKey => IngameKeybinds.Instance.UpgradeStoreCursorExitKey;

		public static InputAction PageUpKey => IngameKeybinds.Instance.UpgradeStorePageUpKey;

		public static InputAction PageDownKey => IngameKeybinds.Instance.UpgradeStorePageDownKey;

		public static InputAction LguStoreConfirmKey => IngameKeybinds.Instance.LguStoreConfirmKey;

		public static InputAction ChangeApplicationSortingKey => IngameKeybinds.Instance.ApplicationChangeSorting;

		internal static void Init()
		{
			IngameKeybinds.Instance = new IngameKeybinds();
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace InteractiveTerminalAPI.NetcodePatcher
{
	[AttributeUsage(AttributeTargets.Module)]
	internal class NetcodePatchedAssemblyAttribute : Attribute
	{
	}
}