Decompiled source of SubTerminalEX v1.1.2

BepInEx/plugins/SubTerminalEX.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
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.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SubTerminalEX.Features;
using SubTerminalEX.Patches;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("SubTerminalEX")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+bfc30f0a4be97d253bb4c6a5f4717959e136cf94")]
[assembly: AssemblyProduct("My first plugin")]
[assembly: AssemblyTitle("SubTerminalEX")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
		}
	}
	[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 SubTerminalEX
{
	internal static class PLog
	{
		private static ManualLogSource? _log;

		private static bool _init;

		public static void InitLog(ManualLogSource logSource)
		{
			if (!_init)
			{
				_log = logSource;
				_init = true;
			}
		}

		public static void Inf(string msg)
		{
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)msg);
			}
		}

		public static void Err(string msg)
		{
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogError((object)msg);
			}
		}

		public static void Dbg(string msg)
		{
			if (Plugin.pluginInstance.DebugMode)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)msg);
				}
			}
		}

		public static void Wrn(string msg)
		{
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogWarning((object)msg);
			}
		}
	}
	[BepInPlugin("com.ozzzzy.subterex", "SubTerminalEX", "1.1.2")]
	internal sealed class Plugin : BaseUnityPlugin
	{
		internal static Harmony? _harmony;

		internal static Plugin pluginInstance;

		internal static bool GameStarted;

		internal bool DebugMode;

		internal bool FastTerminalBoot;

		internal bool EnableAutoload;

		internal string AutoloadTargetFile = string.Empty;

		internal int ticks;

		internal const string ConfigAliasSection = "Alias Settings";

		internal const string ConfigTerminalSection = "Terminal Settings";

		internal static MonoBehaviour Interpreter => (MonoBehaviour)(object)TerminalManager.instance.interpreter;

		private void Awake()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			pluginInstance = this;
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
				_harmony = null;
			}
			SetupConfig();
			CacheConfig();
			PLog.InitLog(((BaseUnityPlugin)this).Logger);
			PLog.Inf("Loaded successfully - version: 1.1.2");
			_harmony = new Harmony("com.ozzzzy.subterex");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				PLog.Wrn("SubTerminalEX is destroyed!, terminating all feature and patches...");
				_harmony.UnpatchSelf();
				_harmony = null;
			}
		}

		private void FixedUpdate()
		{
			if (GameStarted)
			{
				if (ticks < 10)
				{
					ticks++;
					return;
				}
				ticks = 0;
				TerminalCommandManager.Update();
			}
		}

		internal void OnGameStartup()
		{
			TerminalCommandManager.CacheVanillaCommand();
			TerminalCommandManager.UpdateToGame();
			ExtraTerminalCommand.Register();
			GameStarted = true;
			if (EnableAutoload)
			{
				string text = Path.Combine(Environment.CurrentDirectory, AutoloadTargetFile.ToUpper() + ".txt");
				long length = new FileInfo(text).Length;
				if (length <= 1073741824 && File.Exists(text))
				{
					ExtraTerminalCommand._palias_path = text;
					ExtraTerminalCommand._palias_size = (int)length;
					((MonoBehaviour)this).StartCoroutine(ExtraTerminalCommand.ProcessAliasFile());
				}
			}
		}

		internal static T GetValueFromConfigEntry<T>(ConfigEntryBase entry)
		{
			if (entry.BoxedValue == null)
			{
				return (T)entry.DefaultValue;
			}
			return (T)entry.BoxedValue;
		}

		internal void CacheConfig()
		{
			DebugMode = GetValueFromConfigEntry<bool>(((BaseUnityPlugin)this).Config["Debug", "Debug Mode"]);
			FastTerminalBoot = GetValueFromConfigEntry<bool>(((BaseUnityPlugin)this).Config["Terminal Settings", "Skip Bootup Text"]);
			EnableAutoload = GetValueFromConfigEntry<bool>(((BaseUnityPlugin)this).Config["Alias Settings", "Enable Autoload"]);
			AutoloadTargetFile = GetValueFromConfigEntry<string>(((BaseUnityPlugin)this).Config["Alias Settings", "Autoload File"]);
		}

		internal void SetupConfig()
		{
			((BaseUnityPlugin)this).Config.Bind<bool>("Alias Settings", "Enable Autoload", false, "Allow this mod to automatically load your alias definition upon game start");
			((BaseUnityPlugin)this).Config.Bind<string>("Alias Settings", "Autoload File", "aliasAutoLoad", "The target file name to load from");
			((BaseUnityPlugin)this).Config.Bind<bool>("Terminal Settings", "Skip Bootup Text", true, "Skip terminal bootup text");
			((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Debug Mode", false, "Turn on debug mode for mods developer");
			((BaseUnityPlugin)this).Config.Save();
		}
	}
	public static class Shared
	{
		internal static int LevDist(string s1, string s2)
		{
			int[,] array = new int[s1.Length + 1, s2.Length + 1];
			for (int i = 0; i <= s1.Length; i++)
			{
				array[i, 0] = i;
			}
			for (int j = 0; j <= s2.Length; j++)
			{
				array[0, j] = j;
			}
			for (int k = 1; k <= s1.Length; k++)
			{
				for (int l = 1; l <= s2.Length; l++)
				{
					int num = ((s1[k - 1] != s2[l - 1]) ? 1 : 0);
					array[k, l] = Mathf.Min(Mathf.Min(array[k - 1, l] + 1, array[k, l - 1] + 1), array[k - 1, l - 1] + num);
				}
			}
			return array[s1.Length, s2.Length];
		}

		public static string? GetClosestCommand(string inputCommand)
		{
			string inputCommand2 = inputCommand;
			int num = int.MaxValue;
			string result = null;
			foreach (var item3 in from <>h__TransparentIdentifier0 in Enumerable.Select(TerminalCommandManager._cdict, delegate(KeyValuePair<string, TerminalCommandEX> pair)
				{
					string s = inputCommand2;
					KeyValuePair<string, TerminalCommandEX> keyValuePair = pair;
					return new
					{
						pair = pair,
						num2 = LevDist(s, keyValuePair.Key)
					};
				})
				where <>h__TransparentIdentifier0.num2 < num
				select (<>h__TransparentIdentifier0.pair, <>h__TransparentIdentifier0.num2))
			{
				KeyValuePair<string, TerminalCommandEX> item = item3.Item1;
				int item2 = item3.Item2;
				num = item2;
				result = item.Key;
			}
			return result;
		}
	}
	public struct STEHookData
	{
		public Action<List<string>> Func { get; set; }

		public STEHookTarget Target { get; internal set; }

		public STEHookPriority Priority { get; internal set; }

		public int PriorityInt { get; internal set; }

		public string TargetCommand { get; internal set; }

		internal STEHookData(Action<List<string>> func, string command, STEHookTarget target, STEHookPriority prio)
		{
			Func = func;
			Target = target;
			TargetCommand = command;
			Priority = prio;
			PriorityInt = (int)prio;
		}

		internal STEHookData(Action<List<string>> func, string command, STEHookTarget target, int prio)
		{
			Func = func;
			Target = target;
			TargetCommand = command;
			Priority = STEHookPriority.None;
			PriorityInt = prio;
		}
	}
	public enum STEHookPriority
	{
		None = int.MinValue,
		Last = 0,
		ExtremelyLow = 100,
		VeryLow = 250,
		Low = 400,
		Default = 500,
		High = 600,
		VeryHigh = 750,
		ExtremelyHigh = 900,
		First = 1000
	}
	public enum STEHookTarget
	{
		Before = 0,
		After = 1,
		Default = 1
	}
	internal static class SubterexInfo
	{
		internal const string PLUG_GUID = "com.ozzzzy.subterex";

		internal const string PLUG_NAME = "SubTerminalEX";

		internal const string PLUG_VER = "1.1.2";
	}
	public class TerminalCommandEX : ScriptableObject
	{
		public string Command = string.Empty;

		internal string? _alias_original = string.Empty;

		public int NumArgs;

		public string Description = string.Empty;

		public string ParameterDescription = string.Empty;

		public string Example = string.Empty;

		public string[] ArgTips = Array.Empty<string>();

		internal string actionMethodName = string.Empty;

		public Func<List<string>, IEnumerator>? ActionMethod;

		public Action<string, List<string>, STEHookTarget>? HookMethod;

		public bool ArgsOptional = true;

		public bool Hidden;

		public bool ForceExactArgument = true;

		internal bool CheckArgs(List<string> args)
		{
			if (ForceExactArgument)
			{
				return args.Count - 1 == NumArgs;
			}
			return args.Count - 1 >= NumArgs;
		}

		internal TerminalCommandEX()
		{
		}

		internal static TerminalCommandEX Create()
		{
			return ScriptableObject.CreateInstance<TerminalCommandEX>();
		}

		public static implicit operator TerminalCommandEX(TerminalCommand cmd)
		{
			TerminalCommandEX terminalCommandEX = Create();
			terminalCommandEX.Command = cmd.command;
			terminalCommandEX.NumArgs = cmd.numArgs;
			terminalCommandEX.Description = cmd.description;
			terminalCommandEX.ParameterDescription = cmd.parameterDescription;
			terminalCommandEX.Example = cmd.example;
			terminalCommandEX.ArgTips = cmd.argTips;
			terminalCommandEX.actionMethodName = cmd.actionMethod;
			terminalCommandEX.ArgsOptional = cmd.argsOptional;
			terminalCommandEX.Hidden = cmd.hidden;
			return terminalCommandEX;
		}

		public static implicit operator TerminalCommand(TerminalCommandEX tex)
		{
			TerminalCommand obj = ScriptableObject.CreateInstance<TerminalCommand>();
			obj.command = tex.Command;
			obj.numArgs = tex.NumArgs;
			obj.description = tex.Description;
			obj.parameterDescription = tex.ParameterDescription;
			obj.example = tex.Example;
			obj.argTips = tex.ArgTips;
			obj.actionMethod = tex.actionMethodName;
			obj.argsOptional = tex.ArgsOptional;
			obj.hidden = tex.Hidden;
			return obj;
		}
	}
	public static class TerminalCommandManager
	{
		internal static readonly Dictionary<string, TerminalCommandEX> _cdict = new Dictionary<string, TerminalCommandEX>();

		internal static readonly List<TerminalCommandEX> _clist = new List<TerminalCommandEX>();

		internal static readonly List<TerminalCommandEX> _cextra = new List<TerminalCommandEX>();

		internal static readonly Dictionary<string, LinkedList<STEHookData>[]> _chook = new Dictionary<string, LinkedList<STEHookData>[]>();

		internal static bool _lastModified = false;

		internal static void Update(bool force = false)
		{
			if (_lastModified || force)
			{
				UpdateToGame();
			}
		}

		internal static void CacheVanillaCommand()
		{
			TerminalCommand[] commands = TerminalManager.instance.commands;
			foreach (TerminalCommand val in commands)
			{
				if (!_cdict.ContainsKey(val.command))
				{
					_cdict.Add(val.command, val);
					_clist.Add(val);
				}
			}
		}

		public static bool RemoveCommand(string command)
		{
			if (_cdict.ContainsKey(command))
			{
				TerminalCommandEX terminalCommandEX = _cdict[command];
				_cdict.Remove(command);
				_clist.Remove(terminalCommandEX);
				_cextra.Remove(terminalCommandEX);
				Object.Destroy((Object)(object)terminalCommandEX);
				return true;
			}
			return false;
		}

		internal static void UpdateToGame()
		{
			int num = TerminalManager.instance.commands.Length;
			int num2 = _clist.Count + _cextra.Count;
			if (num2 == num)
			{
				_lastModified = false;
				return;
			}
			TerminalCommand[] array = (TerminalCommand[])(object)new TerminalCommand[num2];
			int count = _clist.Count;
			int count2 = _cextra.Count;
			for (int i = 0; i < count; i++)
			{
				array[i] = _clist[i];
			}
			for (int j = 0; j < count2; j++)
			{
				array[j + count] = _cextra[j];
			}
			_lastModified = false;
			TerminalManager.instance.commands = array;
		}

		public static bool AddNoArgumentCommand(string command, Func<List<string>, IEnumerator> onInvoke, string name = "", string description = "", string example = "", bool hidden = false)
		{
			command = command.ToUpper();
			if (_cdict.ContainsKey(command))
			{
				return false;
			}
			TerminalCommandEX terminalCommandEX = TerminalCommandEX.Create();
			terminalCommandEX.Hidden = hidden;
			((Object)terminalCommandEX).name = name;
			terminalCommandEX.Description = description;
			terminalCommandEX.Command = command;
			terminalCommandEX.ActionMethod = onInvoke;
			terminalCommandEX.Example = example;
			terminalCommandEX.actionMethodName = "";
			terminalCommandEX.ForceExactArgument = false;
			terminalCommandEX.ArgsOptional = true;
			terminalCommandEX.NumArgs = 0;
			terminalCommandEX.ParameterDescription = string.Empty;
			terminalCommandEX.ArgTips = Array.Empty<string>();
			_cdict.Add(command, terminalCommandEX);
			_cextra.Add(terminalCommandEX);
			_lastModified = true;
			return true;
		}

		public static bool AddCommand(string command, Func<List<string>, IEnumerator> onInvoke, string name = "", string description = "", int argAmount = 0, bool forceExactArgumentCount = false, bool argOptional = true, string parameterDesc = "", string[]? argumentTips = null, string example = "", bool hidden = false)
		{
			command = command.ToUpper();
			if (_cdict.ContainsKey(command))
			{
				return false;
			}
			TerminalCommandEX terminalCommandEX = TerminalCommandEX.Create();
			terminalCommandEX.Hidden = hidden;
			((Object)terminalCommandEX).name = name;
			terminalCommandEX.Description = description;
			terminalCommandEX.Command = command;
			terminalCommandEX.NumArgs = argAmount;
			terminalCommandEX.ParameterDescription = parameterDesc;
			terminalCommandEX.ActionMethod = onInvoke;
			terminalCommandEX.actionMethodName = "";
			terminalCommandEX.ArgsOptional = argOptional;
			terminalCommandEX.ArgTips = argumentTips ?? new string[1] { "" };
			terminalCommandEX.Example = example;
			terminalCommandEX.ForceExactArgument = forceExactArgumentCount;
			_cdict.Add(command, terminalCommandEX);
			_cextra.Add(terminalCommandEX);
			_lastModified = true;
			return true;
		}

		public static bool AliasCommand(string oldCommand, string newAlias, bool addToUserList = false)
		{
			oldCommand = oldCommand.ToUpper();
			newAlias = newAlias.ToUpper();
			if (!_cdict.ContainsKey(oldCommand))
			{
				return false;
			}
			if (_cdict.ContainsKey(newAlias))
			{
				return false;
			}
			TerminalCommandEX terminalCommandEX = _cdict[oldCommand];
			TerminalCommandEX terminalCommandEX2 = TerminalCommandEX.Create();
			terminalCommandEX2.Command = newAlias;
			terminalCommandEX2._alias_original = oldCommand;
			terminalCommandEX2.Hidden = terminalCommandEX.Hidden;
			((Object)terminalCommandEX2).name = ((Object)terminalCommandEX).name;
			terminalCommandEX2.Description = terminalCommandEX.Description;
			terminalCommandEX2.NumArgs = terminalCommandEX.NumArgs;
			terminalCommandEX2.ParameterDescription = terminalCommandEX.ParameterDescription;
			terminalCommandEX2.ActionMethod = terminalCommandEX.ActionMethod;
			terminalCommandEX2.actionMethodName = terminalCommandEX.actionMethodName;
			terminalCommandEX2.ArgsOptional = terminalCommandEX.ArgsOptional;
			terminalCommandEX2.ArgTips = terminalCommandEX.ArgTips;
			terminalCommandEX2.Example = terminalCommandEX.Example;
			if (!string.IsNullOrWhiteSpace(terminalCommandEX.actionMethodName))
			{
				terminalCommandEX2.ForceExactArgument = true;
			}
			_cdict.Add(newAlias, terminalCommandEX2);
			_cextra.Add(terminalCommandEX2);
			ExtraTerminalCommand._aliasList.Add(newAlias);
			_lastModified = true;
			return true;
		}

		public static bool OverrideCommand(string oldCommand, Func<List<string>, IEnumerator> onInvoke, string? name = null, string? description = null, int? argAmount = null, bool? argOptional = null, string? parameterDesc = null, string[]? argumentTips = null, string? example = null, bool? hidden = null, bool? forceExactArgumentCount = false)
		{
			oldCommand = oldCommand.ToUpper();
			if (!_cdict.ContainsKey(oldCommand))
			{
				return false;
			}
			TerminalCommandEX terminalCommandEX = _cdict[oldCommand];
			terminalCommandEX.Hidden = hidden ?? terminalCommandEX.Hidden;
			((Object)terminalCommandEX).name = name ?? ((Object)terminalCommandEX).name;
			terminalCommandEX.Description = description ?? terminalCommandEX.Description;
			terminalCommandEX.NumArgs = argAmount ?? terminalCommandEX.NumArgs;
			terminalCommandEX.ParameterDescription = parameterDesc ?? terminalCommandEX.ParameterDescription;
			terminalCommandEX.ActionMethod = onInvoke;
			terminalCommandEX.actionMethodName = string.Empty;
			terminalCommandEX.ForceExactArgument = forceExactArgumentCount.GetValueOrDefault();
			terminalCommandEX.ArgsOptional = argOptional ?? terminalCommandEX.ArgsOptional;
			terminalCommandEX.ArgTips = argumentTips ?? terminalCommandEX.ArgTips;
			terminalCommandEX.Example = example ?? terminalCommandEX.Example;
			return true;
		}

		public static bool HookCommand(string targetCommand, Action<List<string>> func, STEHookPriority priority = STEHookPriority.Default, STEHookTarget hookTarget = STEHookTarget.After)
		{
			targetCommand = targetCommand.ToUpper();
			if (!_cdict.ContainsKey(targetCommand))
			{
				return false;
			}
			if (_chook.TryGetValue(targetCommand, out LinkedList<STEHookData>[] value))
			{
				LinkedList<STEHookData> linkedList = value[(int)hookTarget];
				STEHookData value2 = new STEHookData(func, targetCommand, hookTarget, (priority == STEHookPriority.None) ? STEHookPriority.Default : priority);
				LinkedListNode<STEHookData> linkedListNode = linkedList.First;
				if (linkedListNode == null)
				{
					linkedList.AddFirst(value2);
					return true;
				}
				while (true)
				{
					if (linkedListNode.Value.Priority < priority)
					{
						linkedList.AddBefore(linkedListNode, value2);
					}
					if (linkedListNode.Next == null)
					{
						break;
					}
					linkedListNode = linkedListNode.Next;
				}
				linkedList.AddAfter(linkedListNode, value2);
				return true;
			}
			_cdict[targetCommand].HookMethod = delegate(string cmd, List<string> args, STEHookTarget executeTarget)
			{
				if (_chook.TryGetValue(cmd, out LinkedList<STEHookData>[] value3))
				{
					for (LinkedListNode<STEHookData> linkedListNode2 = value3[(int)executeTarget].First; linkedListNode2 != null; linkedListNode2 = linkedListNode2.Next)
					{
						try
						{
							linkedListNode2.Value.Func(args);
						}
						catch
						{
							PLog.Err("Exception caught upon executing hook of \"" + linkedListNode2.Value.TargetCommand + "\" command");
							if (Plugin.pluginInstance.DebugMode)
							{
								throw;
							}
						}
					}
				}
			};
			value = new LinkedList<STEHookData>[2];
			LinkedList<STEHookData> linkedList2 = new LinkedList<STEHookData>();
			LinkedList<STEHookData> linkedList3 = new LinkedList<STEHookData>();
			value[0] = linkedList2;
			value[1] = linkedList3;
			value[(int)hookTarget].AddFirst(new STEHookData(func, targetCommand, hookTarget, priority));
			_chook.Add(targetCommand, value);
			return true;
		}

		public static bool HookCommand(string targetCommand, Action<List<string>> func, int priority = 500, STEHookTarget hookTarget = STEHookTarget.After)
		{
			targetCommand = targetCommand.ToUpper();
			if (!_cdict.ContainsKey(targetCommand))
			{
				return false;
			}
			if (_chook.TryGetValue(targetCommand, out LinkedList<STEHookData>[] value))
			{
				LinkedList<STEHookData> linkedList = value[(int)hookTarget];
				STEHookData value2 = new STEHookData(func, targetCommand, hookTarget, priority);
				LinkedListNode<STEHookData> linkedListNode = linkedList.First;
				if (linkedListNode == null)
				{
					linkedList.AddFirst(value2);
					return true;
				}
				while (true)
				{
					if (linkedListNode.Value.PriorityInt < priority)
					{
						linkedList.AddBefore(linkedListNode, value2);
					}
					if (linkedListNode.Next == null)
					{
						break;
					}
					linkedListNode = linkedListNode.Next;
				}
				linkedList.AddAfter(linkedListNode, value2);
				return true;
			}
			_cdict[targetCommand].HookMethod = delegate(string cmd, List<string> args, STEHookTarget executeTarget)
			{
				if (_chook.TryGetValue(cmd, out LinkedList<STEHookData>[] value3))
				{
					for (LinkedListNode<STEHookData> linkedListNode2 = value3[(int)executeTarget].First; linkedListNode2 != null; linkedListNode2 = linkedListNode2.Next)
					{
						try
						{
							linkedListNode2.Value.Func(args);
						}
						catch
						{
							PLog.Err("Exception caught upon executing hook of \"" + linkedListNode2.Value.TargetCommand + "\" command");
							if (Plugin.pluginInstance.DebugMode)
							{
								throw;
							}
						}
					}
				}
			};
			value = new LinkedList<STEHookData>[2];
			LinkedList<STEHookData> linkedList2 = new LinkedList<STEHookData>();
			LinkedList<STEHookData> linkedList3 = new LinkedList<STEHookData>();
			value[0] = linkedList2;
			value[1] = linkedList3;
			value[(int)hookTarget].AddFirst(new STEHookData(func, targetCommand, hookTarget, priority));
			_chook.Add(targetCommand, value);
			return true;
		}
	}
}
namespace SubTerminalEX.Patches
{
	[HarmonyPatch(typeof(NetworkManager), "OnJoinedRoom")]
	internal class NetworkManagerOnJoinedRoomPatches
	{
		[HarmonyPostfix]
		[HarmonyWrapSafe]
		internal static void Postfix()
		{
			Plugin.pluginInstance.OnGameStartup();
		}
	}
	[HarmonyPatch(typeof(TerminalInterpreter), "Interpret")]
	internal static class TerminalInterpreterInterpretPatches
	{
		internal static bool _fieldCached;

		internal static FieldRef<TerminalInterpreter, List<string>> tiArgs;

		internal static AudioClip errorClip;

		internal static AudioClip buyClip;

		internal static TerminalInterpreter instance;

		private static void Cache(TerminalInterpreter term)
		{
			tiArgs = AccessTools.FieldRefAccess<TerminalInterpreter, List<string>>("args");
			errorClip = term.errorClip;
			buyClip = term.buyClip;
			instance = term;
			_fieldCached = true;
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyWrapSafe]
		public static bool Prefix(ref string userInput, ref TerminalInterpreter __instance)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			if (!_fieldCached)
			{
				Cache(__instance);
			}
			PLog.Dbg("Running: " + userInput);
			ref List<string> reference = ref tiArgs.Invoke(__instance);
			reference.Clear();
			string[] array = userInput.TrimStart(Array.Empty<char>()).Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0)
			{
				return false;
			}
			if (array[0].StartsWith("\""))
			{
				TerminalManager.instance.QueueTextLine("ERROR: command can not start with \" character", default(Vector2), 0.075f, (AudioClip)null, 0f);
				return false;
			}
			reference.Add(array[0]);
			int i = 1;
			int num = array.Length;
			StringBuilder stringBuilder = new StringBuilder();
			for (; i < num; i++)
			{
				if (array[i].StartsWith("\""))
				{
					string text = array[i];
					stringBuilder.Append(text.Substring(1));
					stringBuilder.Append(' ');
					bool flag = false;
					while (i < num)
					{
						i++;
						text = array[i];
						if (text.EndsWith("\""))
						{
							stringBuilder.Append(text.Substring(0, text.Length - 1));
							reference.Add(stringBuilder.ToString());
							stringBuilder.Clear();
							flag = true;
							break;
						}
						stringBuilder.Append(text);
						stringBuilder.Append(' ');
					}
					if (!flag)
					{
						TerminalManager.instance.QueueTextLine("ERROR: never ending string argument detected!", default(Vector2), 0.075f, (AudioClip)null, 0f);
						return false;
					}
				}
				else
				{
					reference.Add(array[i]);
				}
			}
			reference[0] = reference[0].Replace("\\", "").Replace("/", "");
			string text2 = reference[0];
			if (!(text2 == "Y"))
			{
				if (text2 == "N")
				{
					reference[0] = "NO";
				}
			}
			else
			{
				reference[0] = "YES";
			}
			if ((int)__instance.currentPrompt != 0 && reference[0] != "NO" && reference[0] != "YES")
			{
				__instance.currentPrompt = (Prompts)0;
			}
			PLog.Dbg("Args: ");
			foreach (string item in reference)
			{
				PLog.Dbg(item);
			}
			string text3 = reference[0];
			if (!TerminalCommandManager._cdict.TryGetValue(text3, out TerminalCommandEX value))
			{
				string closestCommand = Shared.GetClosestCommand(reference[0]);
				if (closestCommand != null)
				{
					TerminalManager.instance.QueueTextLine("Command not recognized. Did you mean " + closestCommand + "?", new Vector2(1f, 1f), 0.075f, (AudioClip)null, 0f);
					return false;
				}
				closestCommand = Shared.GetClosestCommand(userInput);
				if (closestCommand != null)
				{
					TerminalManager.instance.QueueTextLine("Command not recognized. Did you mean " + closestCommand + "?", new Vector2(1f, 1f), 0.075f, (AudioClip)null, 0f);
					return false;
				}
				TerminalManager.instance.QueueTextLine("Command not recognized. Use \"HELP\" for a list of commands.", new Vector2(1f, 1f), 0.075f, (AudioClip)null, 0f);
				return false;
			}
			PLog.Dbg("Command " + text3 + " is valid, running it action method keyed " + value.Command);
			if (!value.ArgsOptional && !value.CheckArgs(reference))
			{
				TerminalManager.instance.QueueTextLine("Incorrect use of parameters.  Use \"HELP\" for more info.", default(Vector2), 0.075f, (AudioClip)null, 0f);
				TerminalManager.instance.QueueTextLine("Expected parameters and usage example:", new Vector2(1f, 1f), 0.075f, (AudioClip)null, 0f);
				TerminalManager.instance.QueueTextLine(value.Command, default(Vector2), 0.075f, (AudioClip)null, 0f);
				TerminalManager.instance.QueueTextLine("                Parameters:   " + value.ParameterDescription, default(Vector2), 0.075f, (AudioClip)null, 0f);
				TerminalManager.instance.QueueTextLine("                Example:      " + value.Example, new Vector2(0f, 1f), 0.075f, (AudioClip)null, 0f);
				return false;
			}
			reference.RemoveAt(0);
			if (value.ForceExactArgument && reference.Count > value.NumArgs)
			{
				reference.RemoveRange(value.NumArgs, reference.Count);
			}
			value.HookMethod?.Invoke(value.Command, reference, STEHookTarget.Before);
			if (value.ActionMethod != null)
			{
				((MonoBehaviour)__instance).StartCoroutine(value.ActionMethod(reference));
			}
			if (!string.IsNullOrWhiteSpace(value.actionMethodName))
			{
				((MonoBehaviour)__instance).StartCoroutine(value.actionMethodName);
			}
			value.HookMethod?.Invoke(value.Command, reference, STEHookTarget.After);
			return false;
		}
	}
	[HarmonyPatch(typeof(TerminalManager), "Awake")]
	internal static class TerminalManagerAwakePatches
	{
		[HarmonyPostfix]
		[HarmonyWrapSafe]
		internal static void Postfix(ref TerminalManager __instance)
		{
			if (Plugin.pluginInstance.FastTerminalBoot)
			{
				__instance.skipBoot = true;
			}
		}
	}
}
namespace SubTerminalEX.Features
{
	internal static class ExtraTerminalCommand
	{
		internal static FieldRef<TerminalManager, int> _TerminalManager_lastDestroyedLine;

		internal static readonly HashSet<string> _aliasList = new HashSet<string>();

		internal static string _palias_path = string.Empty;

		internal static int _palias_size = 0;

		internal static MethodInfo _hatlist;

		internal static MethodInfo _hatbuy;

		internal static MethodInfo _upgradelist;

		internal static MethodInfo _upgradebuy;

		internal static void ChangeLastDestroyedLine(TerminalManager term)
		{
			_TerminalManager_lastDestroyedLine.Invoke(term) = 0;
		}

		internal static IEnumerator CommandClear(List<string> _)
		{
			TerminalManager instance = TerminalManager.instance;
			foreach (Transform item in instance.messageList.transform)
			{
				Transform val = item;
				if (((Object)val).name != "UserInputLine")
				{
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
			instance.messageList.GetComponent<RectTransform>().sizeDelta = new Vector2(1920f, 160f);
			instance.response.Clear();
			ChangeLastDestroyedLine(instance);
			instance.EnableInput();
			yield break;
		}

		internal static IEnumerator ProcessAliasFile()
		{
			int zt = 0;
			string[] str;
			if (_palias_size < 33554432)
			{
				str = File.ReadAllText(_palias_path, Encoding.UTF8).Split(new char[2] { '\n', ',' }, StringSplitOptions.RemoveEmptyEntries);
				if (_palias_size > 16777216)
				{
					yield return (object)new WaitForEndOfFrame();
				}
			}
			else
			{
				StringBuilder sb = new StringBuilder();
				FileStream std = File.Open(_palias_path, FileMode.Open, FileAccess.Read, FileShare.None);
				byte[] arr = new byte[4096];
				while (true)
				{
					int num = std.Read(arr, 0, 4096);
					for (int i = 0; i < num; i++)
					{
						sb.Append(arr[i]);
					}
					Array.Clear(arr, 0, num);
					if (num < 4096)
					{
						break;
					}
					zt++;
					if (zt >= 10)
					{
						zt = 0;
						yield return (object)new WaitForEndOfFrame();
					}
				}
				str = sb.ToString().Split(new char[2] { '\n', ',' }, StringSplitOptions.RemoveEmptyEntries);
				sb.Clear();
				std.Dispose();
				yield return (object)new WaitForEndOfFrame();
			}
			zt = 0;
			string[] array = str;
			foreach (string item in array)
			{
				if (zt >= 100)
				{
					zt = 0;
					yield return (object)new WaitForEndOfFrame();
				}
				if (string.IsNullOrWhiteSpace(item))
				{
					continue;
				}
				string[] array2 = item.Split(new char[1] { ' ' });
				if (array2.Length >= 2)
				{
					int num2 = ((array2[0] == " ") ? 1 : 0);
					_ = array2[num2];
					_ = array2[num2 + 1];
					if (TerminalCommandManager.AliasCommand(array2[num2], array2[num2 + 1]))
					{
						_aliasList.Add(array2[num2 + 1]);
					}
					zt++;
				}
			}
			TerminalManager instance = TerminalManager.instance;
			instance.QueueTextLine("Successfully loaded alias file", default(Vector2), 0.075f, (AudioClip)null, 0f);
			instance.EnableInput();
		}

		internal static IEnumerator CommandAlias(List<string> args)
		{
			string text = args[0];
			TerminalManager instance = TerminalManager.instance;
			switch (text)
			{
			case "SET":
			case "MAP":
			{
				if (args.Count < 3)
				{
					instance.QueueTextLine($"ERROR: mapping command require 2 argument, received {args.Count - 1}", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				string text2 = args[1];
				string text3 = args[2];
				if (!TerminalCommandManager._cdict.ContainsKey(text2))
				{
					instance.QueueTextLine("ERROR: Can not map to non-existences command \"" + text2 + "\"", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				if (TerminalCommandManager.AliasCommand(text2, text3))
				{
					_aliasList.Add(text3);
				}
				instance.QueueTextLine("Successfully map \"" + text3 + "\" to \"" + text2 + "\"", default(Vector2), 0.075f, (AudioClip)null, 0f);
				break;
			}
			case "REM":
			case "REMOVE":
			case "RM":
			{
				if (args.Count < 2)
				{
					instance.QueueTextLine("ERROR: remove mapped alias command require 1 argument, received 0", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				string text2 = args[1];
				if (!_aliasList.Contains(text2))
				{
					instance.QueueTextLine("ERROR: Can not remove non-existences alias \"" + text2 + "\"", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				_aliasList.Remove(text2);
				TerminalCommandManager.RemoveCommand(text2);
				instance.QueueTextLine("Successfully removed alias \"" + text2 + "\"", default(Vector2), 0.075f, (AudioClip)null, 0f);
				break;
			}
			case "CLEAR":
			case "RESET":
			{
				if (_aliasList.Count <= 0)
				{
					instance.QueueTextLine("ERROR: Can not clear alias because none exists", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				int num = _aliasList.Where((string item) => TerminalCommandManager.RemoveCommand(item)).Count();
				instance.QueueTextLine($"Successfully removed {num} mapped alias", default(Vector2), 0.075f, (AudioClip)null, 0f);
				break;
			}
			case "GEN":
			case "GENERATE":
			{
				if (args.Count < 2)
				{
					instance.QueueTextLine("ERROR: generate alias file require 1 argument, received 0", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				string text2 = args[1];
				string text4 = Path.Combine(Environment.CurrentDirectory, text2 + ".txt");
				FileStream fileStream = File.Open(text4, FileMode.Create, FileAccess.Write, FileShare.None);
				StreamWriter streamWriter = new StreamWriter(fileStream, Encoding.UTF8);
				foreach (string alias in _aliasList)
				{
					string alias_original = TerminalCommandManager._cdict[alias]._alias_original;
					streamWriter.Write(alias_original);
					streamWriter.Write(' ');
					streamWriter.Write(alias);
					streamWriter.Write(',');
					streamWriter.Flush();
				}
				fileStream.SetLength(fileStream.Length - 1);
				fileStream.Flush();
				streamWriter.Close();
				instance.QueueTextLine("Successfully wrote to " + text2 + ".txt", default(Vector2), 0.075f, (AudioClip)null, 0f);
				break;
			}
			case "LOAD":
			{
				if (args.Count < 2)
				{
					instance.QueueTextLine("ERROR: load alias file require 1 argument, received 0", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				string text2 = args[1];
				string text4 = Path.Combine(Environment.CurrentDirectory, text2 + ".txt");
				if (!File.Exists(text4))
				{
					instance.QueueTextLine("ERROR: Can not load non-existence alias file", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				long length = new FileInfo(text4).Length;
				if (length > 1073741824)
				{
					instance.QueueTextLine("ERROR: Will not load alias file larger than 1GB", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				if (_aliasList.Count > 0)
				{
					foreach (string alias2 in _aliasList)
					{
						TerminalCommandManager.RemoveCommand(alias2);
					}
				}
				instance.QueueTextLine("Loading pre-defined alias text file named: " + text2 + ".txt", default(Vector2), 0.075f, (AudioClip)null, 0f);
				instance.QueueTextLine("WARN: This operation may took a long time", default(Vector2), 0.075f, (AudioClip)null, 0f);
				_palias_path = text4;
				_palias_size = (int)length;
				Plugin.Interpreter.StartCoroutine(ProcessAliasFile());
				instance.inputEnabled = false;
				break;
			}
			default:
			{
				if (args.Count < 2)
				{
					instance.QueueTextLine($"ERROR: mapping command require 2 argument, received {args.Count}", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				string text2 = args[0];
				string text3 = args[1];
				if (!TerminalCommandManager._cdict.ContainsKey(text2))
				{
					instance.QueueTextLine("ERROR: Can not map to non-existences command \"" + text2 + "\"", default(Vector2), 0.075f, (AudioClip)null, 0f);
					break;
				}
				if (TerminalCommandManager.AliasCommand(text2, text3))
				{
					_aliasList.Add(text3);
				}
				instance.QueueTextLine("Successfully map \"" + text3 + "\" to \"" + text2 + "\"", default(Vector2), 0.075f, (AudioClip)null, 0f);
				break;
			}
			}
			yield break;
		}

		internal static IEnumerator HatShop(List<string> arg)
		{
			return (IEnumerator)_hatlist.Invoke(TerminalInterpreterInterpretPatches.instance, null);
		}

		internal static IEnumerator HatBuy(List<string> arg)
		{
			return (IEnumerator)_hatbuy.Invoke(TerminalInterpreterInterpretPatches.instance, null);
		}

		internal static IEnumerator UpgradeShop(List<string> arg)
		{
			return (IEnumerator)_upgradelist.Invoke(TerminalInterpreterInterpretPatches.instance, null);
		}

		internal static IEnumerator UpgradeBuy(List<string> arg)
		{
			return (IEnumerator)_upgradebuy.Invoke(TerminalInterpreterInterpretPatches.instance, null);
		}

		internal static void Register()
		{
			TerminalCommandManager.AddNoArgumentCommand("clear", CommandClear, "Clear terminal", "Clear the terminal");
			TerminalCommandManager.AliasCommand("clear", "cls");
			_TerminalManager_lastDestroyedLine = AccessTools.FieldRefAccess<TerminalManager, int>("lastDestroyedLine");
			TerminalCommandManager.AddCommand("alias", CommandAlias, "Alias system", "Create terminal alias", 1, forceExactArgumentCount: false, argOptional: false, "[kind] [args]", new string[1] { "" }, "alias set view_cam vcam");
			_hatlist = AccessTools.Method("TerminalInterpreter:OpenHatShopCommand", (Type[])null, (Type[])null);
			_hatbuy = AccessTools.Method("TerminalInterpreter:BuyHatCommand", (Type[])null, (Type[])null);
			_upgradelist = AccessTools.Method("TerminalInterpreter:OpenUpgradeShopCommand", (Type[])null, (Type[])null);
			_upgradebuy = AccessTools.Method("TerminalInterpreter:BuyUpgradeCommand", (Type[])null, (Type[])null);
			TerminalCommandManager.AddCommand("hats", HatShop);
			TerminalCommandManager.AddCommand("buy_hat", HatBuy, "", "", 1, forceExactArgumentCount: true);
			TerminalCommandManager.AddCommand("upgrades", UpgradeShop);
			TerminalCommandManager.AddCommand("buy_upgrade", UpgradeBuy, "", "", 1, forceExactArgumentCount: true);
		}
	}
}